国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

理解Javascript中的事件綁定與事件委托

lewinlee / 855人閱讀

摘要:最近在深入實(shí)踐中,遇到了一些問(wèn)題,比如我需要為動(dòng)態(tài)創(chuàng)建的元素綁定事件,那么普通的事件綁定就不行了,于是通過(guò)上網(wǎng)查資料了解到事件委托,因此想總結(jié)一下中的事件綁定與事件委托。事件冒泡認(rèn)為事件促發(fā)的最深層元素首先接收事件。

最近在深入實(shí)踐js中,遇到了一些問(wèn)題,比如我需要為動(dòng)態(tài)創(chuàng)建的DOM元素綁定事件,那么普通的事件綁定就不行了,于是通過(guò)上網(wǎng)查資料了解到事件委托,因此想總結(jié)一下js中的事件綁定與事件委托。

事件綁定 最直接的事件綁定:HTML事件處理程序

如下示例代碼,通過(guò)節(jié)點(diǎn)屬性顯式聲明,直接在HTML中,顯式地為按鈕綁定了click事件,當(dāng)該按鈕有用戶點(diǎn)擊行為時(shí),便會(huì)觸發(fā)myClickFunc方法。

/* html */


/* js */
// 事件處理程序
var myClickFunc = function(evt){
    // TODO..
};

// 移除事件處理程序
myClickFunc = function(){};

顯而易見(jiàn),這種綁定方式非常不友好,HTML代碼和JS代碼嚴(yán)重耦合在一起,比如當(dāng)要修改一個(gè)函數(shù)名時(shí)候,就要修改兩次,

DOM 0 級(jí)事件處理程序

通過(guò)DOM操作動(dòng)態(tài)綁定事件,是一種比較傳統(tǒng)的方式,把一個(gè)函數(shù)賦值給事件處理程序。這種方式也是應(yīng)用較多的方式,比較簡(jiǎn)單。看下面例子:

/* html */


/* js */
// 事件處理程序
var myClickFunc = function(evt){
    // TODO ...
};

// 直接給DOM節(jié)點(diǎn)的 onclick 方法賦值,注意這里接收的是一個(gè)function
document.getElementById("btn").onclick = myClickFunc;

// 移除事件處理程序
document.getElementById("btn").onclick = null;
DOM 2 級(jí)事件處理程序

通過(guò)事件監(jiān)聽(tīng)的方式綁定事件,DOM2級(jí)事件定義了兩個(gè)方法,用于處理指定和刪除事件處理程序的操作。

// event: 事件名稱
// function: 事件函數(shù)
// boolean: false | true, true 為事件捕獲, false 為事件冒泡(默認(rèn));
Ele.addEventListener(event,function[,boolean]); // 添加句柄
ELe.removeEventListener(event,function[,boolean]); // 移除句柄

看個(gè)例子:

/* html */


/* js */
// 通過(guò)DOM操作進(jìn)行動(dòng)態(tài)綁定:
// 獲取btnHello節(jié)點(diǎn)
var oBtn = document.getElementById("btn");
 
// 增加第一個(gè) click 事件監(jiān)聽(tīng)處理程序
oBtn.addEventListener("click",function(evt){
    // TODO sth 1...
});
 
// 增加第二個(gè) click 事件監(jiān)聽(tīng)處理程序
oBtn.addEventListener("click",function(evt){
    // TODO sth 2...
});

// ps:通過(guò)這種形式,可以給btn按鈕綁定任意多個(gè)click監(jiān)聽(tīng);注意,執(zhí)行順序與添加順序相關(guān)。

// 移除事件處理程序
oBtn.removeEventListener("click",function(evt){..});
IE事件處理程序

DOM 2級(jí)事件處理程序在IE是行不通的,IE有自己的事件處理程序方法:attachEvent()detachEvent()。這兩個(gè)方法的用法與addEventListener()是一樣的,但是只接收兩個(gè)參數(shù),一個(gè)是事件名稱,另一個(gè)是事件處理程序的函數(shù)。為什么不使用第三個(gè)參數(shù)的原因呢?因?yàn)镮E8以及更早的瀏覽器版本只支持事件冒泡。看個(gè)例子:

/* html */


/* js */
var oBtn = document.getElementById("btn");
// 事件處理函數(shù)
function evtFn(){ 
    console.log(this);
}
// 添加句柄
oBtn.attachEvent("onclick",evtFn);

// 移除句柄
oBtn.detachEvent("onclick",evtFn);
簡(jiǎn)易的跨瀏覽器解決方法

如果我們既要支持IE的事件處理方法,又要支持 DOM 2級(jí)事件,那么就要封裝一個(gè)跨瀏覽器的事件處理函數(shù),如果支持 DOM 2級(jí)事件,就用addEventListener,否則就用attachEvent。例子如下:

//跨瀏覽器事件處理程序
var eventUtil = {
    // 添加句柄
    addHandler: function(element, type, handler){
        if(element.addEventListener){
            element.addEventListener(type, handler, false);
        }else if(element.attachEvent){
            element.attachEvent("on" + type, handler);
        }else{
            element["on" + type] = handler;
        }
    },
    // 刪除句柄
    removeHandler: function(element, type, handler){
        if(element.removeEventListener){
            element.removeEventListener(type, handler, false);
        }else if(element.detachEvent){
            element.detachEvent("on" + type, handler);
        }else{
            element["on" + type] = null;
        }
    }
};

var oBtn = document.getElementById("btn");
function evtFn(){
    alert("hello world");
}
eventUtil.addHandler(oBtn, "click", evtFn);
eventUtil.removeHandler(oBtn, "click", evtFn);
事件冒泡和事件捕獲

在了解事件委托之前,要先了解下事件冒泡和事件捕獲。

早期的web開(kāi)發(fā),瀏覽器廠商很難回答一個(gè)哲學(xué)上的問(wèn)題:當(dāng)你在頁(yè)面上的一個(gè)區(qū)域點(diǎn)擊時(shí),你真正感興趣的是哪個(gè)元素。這個(gè)問(wèn)題帶來(lái)了交互的定義。在一個(gè)元素的界限內(nèi)點(diǎn)擊,顯得有點(diǎn)含糊。畢竟,在一個(gè)元素上的點(diǎn)擊同時(shí)也發(fā)生在另一個(gè)元素的界限內(nèi)。例如單擊一個(gè)按鈕。你實(shí)際上點(diǎn)擊了按鈕區(qū)域、body元素的區(qū)域以及html元素的區(qū)域。

伴隨著這個(gè)問(wèn)題,兩種主流的瀏覽器Netscape和IE有不同的解決方案。Netscape定義了一種叫做事件捕獲的處理方法,事件首先發(fā)生在DOM樹(shù)的最高層對(duì)象(document)然后往最深層的元素傳播。在圖例中,事件捕獲首先發(fā)生在document上,然后是html元素,body元素,最后是button元素。

IE的處理方法正好相反。他們定義了一種叫事件冒泡的方法。事件冒泡認(rèn)為事件促發(fā)的最深層元素首先接收事件。然后是它的父元素,依次向上,知道document對(duì)象最終接收到事件。盡管相對(duì)于html元素來(lái)說(shuō),document沒(méi)有獨(dú)立的視覺(jué)表現(xiàn),他仍然是html元素的父元素并且事件能冒泡到document元素。所以圖例中噢噢那個(gè)button元素先接收事件,然后是body、html最后是document。如下圖:

事件冒泡

簡(jiǎn)單點(diǎn)說(shuō),事件冒泡就是事件觸發(fā)時(shí),會(huì)從目標(biāo)DOM元素向上傳播,直到文檔根節(jié)點(diǎn),一般情況下,會(huì)是如下形式傳播:

targetDOM → parentNode → ... → body → document → window

如果希望一次事件觸發(fā)能在整個(gè)DOM樹(shù)上都得到響應(yīng),那么就需要用到事件冒泡的機(jī)制??聪旅媸纠?/p>

/* html */


/* js */
// 給按鈕增加click監(jiān)聽(tīng)
document.getElementById("btn").addEventListener("click",function(evt){
    alert("button clicked");
},false);
 
// 給body增加click監(jiān)聽(tīng)
document.body.addEventListener("click",function(evt){
    alert("body clicked");
},false);

在這種情況下,點(diǎn)擊按鈕“ClickMe”后,其自身的click事件會(huì)被觸發(fā),同時(shí),該事件將會(huì)繼續(xù)向上傳播, 所有的祖先節(jié)點(diǎn)都將得到事件的觸發(fā)命令,并立即觸發(fā)自己的click事件;所以如上代碼,將會(huì)連續(xù)彈出兩個(gè)alert.

在有些時(shí)候,我們想讓事件獨(dú)立觸發(fā),所以我們必須阻止冒泡,用eventstopPropagation()方法。



/* js */
// 給按鈕增加click監(jiān)聽(tīng)
document.getElementById("btn").addEventListener("click",function(evt){
    alert("button clicked");
    evt.stopPropagation(); //阻止事件冒泡
},false);
 
// 給body增加click監(jiān)聽(tīng)
document.body.addEventListener("click",function(evt){
    alert("body clicked");
},false);

此時(shí),點(diǎn)擊按鈕后,只會(huì)觸發(fā)按鈕本身的click事件,得到一個(gè)alert效果;該按鈕的點(diǎn)擊事件,不會(huì)向上傳播,body節(jié)點(diǎn)就接收不到此次事件命令。

需要注意的是:

不是所有的事件都能冒泡,如:blur、focus、load、unload都不能

不同的瀏覽器,阻止冒泡的方式也不一樣,在w3c標(biāo)準(zhǔn)中,通過(guò)event.stopPropagation()完成, 在IE中則是通過(guò)自身的event.cancelBubble=true來(lái)完成。

事件委托

事件委托看起來(lái)挺難理解,但是舉個(gè)生活的例子。比如,有三個(gè)同事預(yù)計(jì)會(huì)在周一收到快遞。為簽收快遞,有兩種辦法:一是三個(gè)人在公司門口等快遞;二是委托給前臺(tái)MM代為簽收?,F(xiàn)實(shí)當(dāng)中,我們大都采用委托的方案(公司也不會(huì)容忍那么多員工站在門口就為了等快遞)。前臺(tái)MM收到快遞后,她會(huì)判斷收件人是誰(shuí),然后按照收件人的要求簽收,甚至代為付款。這種方案還有一個(gè)優(yōu)勢(shì),那就是即使公司里來(lái)了新員工(不管多少),前臺(tái)MM也會(huì)在收到寄給新員工的快遞后核實(shí)并代為簽收。舉個(gè)例子

HTML結(jié)構(gòu):

  • item1
  • item2
  • item3
  • item4

如果我們要點(diǎn)擊li標(biāo)簽,彈出里面的內(nèi)容,我們就需要為每個(gè)li標(biāo)簽綁定事件。

(function(){
    var oUlItem = document.getElementById("ul-item");
    var oLi = oUlItem.getElementsByTagName("li");
    for(var i=0, l = oLi.length; i < l; i++){
        oLi[i].addEventListener("click",show);
    };
    function show(e){
        e = e || window.event;
        alert(e.target.innerHTML);
    };
})();

雖然這樣子能夠?qū)崿F(xiàn)我們想要的功能,但是如果這個(gè)UL中的LI子元素頻繁的添加或刪除,我們就需要在每次添加LI的時(shí)候?yàn)樗壎ㄊ录_@就添加了復(fù)雜度,并且造成內(nèi)存開(kāi)銷較大。

更簡(jiǎn)單的方法是利用事件委托,當(dāng)事件被掏到更上層的父節(jié)點(diǎn)的時(shí)候,通過(guò)檢查事件的目標(biāo)對(duì)象(target)來(lái)判斷并獲取事件源LI。

(function(){
    var oUlItem = document.getElementById("ul-item");
    oUlItem.addEventListener("click",show);
    function show(e){
        e = e || window.event;
        var src = e.target;
        if(src && src.nodeName.toLowerCase() === "li"){
            alert(src.innerHTML);
        }
    }
})();

這里我們?yōu)楦腹?jié)點(diǎn)UL添加了點(diǎn)擊事件,當(dāng)點(diǎn)擊子節(jié)點(diǎn)LI標(biāo)簽的時(shí)候,點(diǎn)擊事件會(huì)冒泡到父節(jié)點(diǎn)。父節(jié)點(diǎn)捕獲到事件之后,通過(guò)判斷e.target.nodeName來(lái)判斷是否為我們需要處理的節(jié)點(diǎn),并且通過(guò)e.target拿到了被點(diǎn)擊的Li節(jié)點(diǎn)。從而可以獲取到相應(yīng)的信息,并做處理。

優(yōu)點(diǎn):

通過(guò)上面的介紹,大家應(yīng)該能夠體會(huì)到使用事件委托對(duì)于web應(yīng)用程序帶來(lái)的幾個(gè)優(yōu)點(diǎn):

管理的函數(shù)變少了。不需要為每個(gè)元素都添加監(jiān)聽(tīng)函數(shù)。對(duì)于同一個(gè)父節(jié)點(diǎn)下面類似的子元素,可以通過(guò)委托給父元素的監(jiān)聽(tīng)函數(shù)來(lái)處理事件。

可以方便地動(dòng)態(tài)添加和修改元素,不需要因?yàn)樵氐母膭?dòng)而修改事件綁定。

JavaScript和DOM節(jié)點(diǎn)之間的關(guān)聯(lián)變少了,這樣也就減少了因循環(huán)引用而帶來(lái)的內(nèi)存泄漏發(fā)生的概率。

參考資料

http://www.diguage.com/archives/71.html

http://owenchen.net/?p=15

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/80124.html

相關(guān)文章

  • 我所理解JavaScript 事件委托

    摘要:當(dāng)初學(xué)時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。事件的冒泡,所以才可以在父元素來(lái)監(jiān)聽(tīng)子元素觸發(fā)的事件。事件的冒泡這個(gè)要講一下,在的時(shí)候我們可以設(shè)置事件模型事件冒泡事件捕獲,一般來(lái)說(shuō)都是用事件冒泡的模型。 當(dāng)初學(xué)C#時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。在JavaScript里面也有事件委托的概念,那在JavaScrip...

    vvpvvp 評(píng)論0 收藏0
  • 我所理解JavaScript 事件委托

    摘要:當(dāng)初學(xué)時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。事件的冒泡,所以才可以在父元素來(lái)監(jiān)聽(tīng)子元素觸發(fā)的事件。事件的冒泡這個(gè)要講一下,在的時(shí)候我們可以設(shè)置事件模型事件冒泡事件捕獲,一般來(lái)說(shuō)都是用事件冒泡的模型。 當(dāng)初學(xué)C#時(shí),學(xué)到委托概念的時(shí)候,有點(diǎn)不知所措,在工作后運(yùn)用了很多后才發(fā)現(xiàn)真的好用。在JavaScript里面也有事件委托的概念,那在JavaScrip...

    wushuiyong 評(píng)論0 收藏0
  • 【譯】JavaScript面試問(wèn)題:事件委托和this

    摘要:主題來(lái)自于的典型面試問(wèn)題列表。有多種方法來(lái)處理事件委托。這種方法的缺點(diǎn)是父容器的偵聽(tīng)器可能需要檢查事件來(lái)選擇正確的操作,而元素本身不會(huì)是一個(gè)監(jiān)聽(tīng)器。 showImg(http://fw008950-flywheel.netdna-ssl.com/wp-content/uploads/2014/11/Get-Hired-Fast-How-to-Job-Search-Classifieds...

    浠ラ箍 評(píng)論0 收藏0
  • 簡(jiǎn)單說(shuō) JavaScript中的事件委托(下)

    摘要:說(shuō)明上次我們說(shuō)了一些,關(guān)于中事件委托的基礎(chǔ)知識(shí),這次我們繼續(xù)來(lái)看。可選類型,一個(gè)選擇器,用于指定哪些后代元素可以觸發(fā)綁定的事件。類型,指定的事件處理函數(shù)。 說(shuō)明 上次我們說(shuō)了一些,關(guān)于 JavaScript中事件委托的 基礎(chǔ)知識(shí),這次我們繼續(xù)來(lái)看。 解釋 先來(lái)一段代碼 1 2 ul.onclick...

    MasonEast 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

lewinlee

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<