成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS事件流和事件委托

W_BinaryTree / 610人閱讀

摘要:那什么是事件冒泡呢概念請(qǐng)自行百度,直接上圖。,不支持事件捕獲只支持事件冒泡。即本不該被觸發(fā)的事件被綁定上了事件。

在上一篇《JS知識(shí)點(diǎn)大雜燴》中說到了事件流但沒有詳細(xì)的介紹,這篇文章就來介紹一下事件流。

事件流一共由三個(gè)階段分別是:

1.捕獲階段
2.目標(biāo)階段
3.冒泡階段

事件綁定大家都知道,有DOM0級(jí)(on+type)和DOM2級(jí)(addEventListener),我覺得說那么多概念不好理解,直接看代碼吧,為了方便我就直接使用id來獲取元素。

DOM0級(jí)

box1.onclick = function(){ console.log("box1"); }

輸出了box1這個(gè)我們都知道,再來看一下。

box1.onclick = function(){ console.log("box1"); } box1.onclick = function(){ console.log("box1 two"); }

輸出了box1 two,因?yàn)镈OM0級(jí)會(huì)覆蓋掉之前在同一元素上面的綁定,再來看一下。

box1.onclick = function(){ console.log("box1"); } box2.onclick = function(){ console.log("box2"); } box3.onclick = function(){ console.log("box3"); }


當(dāng)我們點(diǎn)擊box1時(shí)都知道輸出box1,可是當(dāng)我們點(diǎn)擊box3時(shí)彈出什么呢?


你可能會(huì)感覺奇怪,為什么我點(diǎn)擊的box3怎么其他的也會(huì)觸發(fā)?因?yàn)?strong>事件冒泡。那什么是事件冒泡呢?概念請(qǐng)自行百度,直接上圖。


這就叫做事件冒泡,一級(jí)一級(jí)往上冒直到window這里我沒有畫出來。DOM0級(jí)只支持冒泡階段。

DOM2級(jí)

box1.addEventListener("click", function(){ console.log("box1"); },false); box2.addEventListener("click", function(){ console.log("box2"); },false); box3.addEventListener("click", function(){ console.log("box3"); },false);

輸出跟上面是一樣的,因?yàn)槲覀兘壎ㄔ诹嗣芭蓦A段。(true捕獲,false冒泡)。
我們?cè)賮砜纯床东@階段是怎么樣的

box1.addEventListener("click", function(){ console.log("box1"); },true); box2.addEventListener("click", function(){ console.log("box2"); },true); box3.addEventListener("click", function(){ console.log("box3"); },true);

我們點(diǎn)擊box3看到

你可能會(huì)發(fā)現(xiàn)順序反過來了,那這是為什么呢?因?yàn)?strong>事件捕獲,那什么是時(shí)間捕獲呢?概念請(qǐng)自行百度,直接上圖。


這就是捕獲階段,跟冒泡階段完全相反。

那冒泡跟捕獲的執(zhí)行順序是什么樣的呢?我分別在每一個(gè)元素上綁定了兩個(gè)階段的同一事件,我們來看看觸發(fā)的順序。

box1.addEventListener("click", function(){ console.log("box1 捕獲階段"); },true); box2.addEventListener("click", function(){ console.log("box2 捕獲階段"); },true); box3.addEventListener("click", function(){ console.log("box3 捕獲階段"); },true); box1.addEventListener("click", function(){ console.log("box1 冒泡階段"); },false); box2.addEventListener("click", function(){ console.log("box2 冒泡階段"); },false); box3.addEventListener("click", function(){ console.log("box3 冒泡階段"); },false);

我們點(diǎn)擊box3看到,先捕獲后冒泡。

那是不是都這樣呢?我們稍微改動(dòng)一下。

box1.addEventListener("click", function(){
    console.log("box1 捕獲階段");
},true);
box2.addEventListener("click", function(){
    console.log("box2 捕獲階段");
},true);
box1.addEventListener("click", function(){
    console.log("box1 冒泡階段");
},false);
box2.addEventListener("click", function(){
    console.log("box2 冒泡階段");
},false);
box3.addEventListener("click", function(){
    console.log("box3 冒泡階段");
},false);
box3.addEventListener("click", function(){
    console.log("box3 捕獲階段");
},true);  // 將box3的捕獲階段放到box3的冒泡階段后面

看看觸發(fā)的順序是不是還一樣呢?


發(fā)現(xiàn)反過來了,其實(shí)這就叫做目標(biāo)階段吧。在你觸發(fā)事件的目標(biāo)元素身上不區(qū)分冒泡捕獲,按綁定的順序來執(zhí)行。

我們用圖來看一下。


這樣是不是太簡(jiǎn)單我們來一點(diǎn)復(fù)雜的。

box1.addEventListener("click", function(){ console.log("box1 捕獲階段"); },true); box2.addEventListener("click", function(){ console.log("box2 捕獲階段"); },true); box3.addEventListener("click", function(){ console.log("box3 捕獲階段"); },true); box1.addEventListener("click", function(){ console.log("box1 冒泡階段"); },false); box2.addEventListener("click", function(){ console.log("box2 冒泡階段"); },false); box3.addEventListener("click", function(){ console.log("box3 冒泡階段"); },false); box1.onclick = function () { console.log("box1 51561"); } box2.onclick = function () { console.log("box2"); } box3.onclick = function () { console.log("box3"); } box1.onclick = function () { console.log("box1"); }

觸發(fā)順序是什么樣的?(我覺得你最好先自己把答案寫出來)

看看你答對(duì)了沒有

這樣會(huì)不會(huì)太簡(jiǎn)單,換一下順序

box1.onclick = function () {
    console.log("box1 51561");
}
box2.onclick = function () {
    console.log("box2");
}
box3.onclick = function () {
    console.log("box3");
}
box1.onclick = function () {
    console.log("box1");
}
box1.addEventListener("click", function(){
    console.log("box1 捕獲階段");
},true);
box2.addEventListener("click", function(){
    console.log("box2 捕獲階段");
},true);
box1.addEventListener("click", function(){
    console.log("box1 冒泡階段");
},false);
box2.addEventListener("click", function(){
    console.log("box2 冒泡階段");
},false);
box3.addEventListener("click", function(){
    console.log("box3 冒泡階段");
},false);
box3.addEventListener("click", function(){
    console.log("box3 捕獲階段");
},true); 


答對(duì)了嗎?

再說一下冒泡和捕獲

box1.onclick = function () { console.log("box1 51561"); } box2.onclick = function () { console.log("box2"); } box3.onclick = function () { console.log("box3"); } box1.onclick = function () { console.log("box1"); } box1.addEventListener("click", function(){ console.log("box1 捕獲階段"); },true); box2.addEventListener("click", function(){ console.log("box2 捕獲階段"); },true); box1.addEventListener("click", function(){ console.log("box1 冒泡階段"); },false); box2.addEventListener("click", function(){ console.log("box2 冒泡階段"); },false); box3.addEventListener("click", function(){ console.log("box3 冒泡階段"); },false); box3.addEventListener("click", function(){ console.log("box3 捕獲階段"); },true);


你說這樣點(diǎn)擊會(huì)輸出什么?你是不是猶豫了?說明你還是不懂冒泡和捕獲。

不要讓你看到的騙了你,冒泡是DOM結(jié)構(gòu)的父子關(guān)系而不是看起來是不是包裹的關(guān)系。(答案同上面)。

忘了IE了,說一下IE的事件機(jī)制。

IE上面不支持addEventListener但是它有attachEvent

box1.onclick = function () {
    console.log("box1 51561");
}
box2.onclick = function () {
    console.log("box2");
}
box3.onclick = function () {
    console.log("box3");
}
box1.onclick = function () {
    console.log("box1");
}
box1.attachEvent("onclick", function (){
    console.log("box1 attachEvent")
})
box2.attachEvent("onclick", function (){
    console.log("box2 attachEvent")
})
box3.attachEvent("onclick", function (){
    console.log("box3 attachEvent")
})

box1.attachEvent("onclick", function (){
    console.log("box1")
})
box1.attachEvent("onclick", function (){
    console.log("box2")
})
box1.attachEvent("onclick", function (){
    console.log("box3")
})

這個(gè)會(huì)輸出什么?(提示:不會(huì)覆蓋)
答案是:box1 box2 box3
哈哈,開玩笑啊。


是不是很奇怪,IE中該事件是先綁定的后輸出。IE6、7、8,不支持事件捕獲只支持事件冒泡。

阻止事件冒泡兼容

我們先來說一下不支持冒泡的事件:blur、focus、mouseenter、mouseleave。(我就知道這些)
還是這個(gè)例子,我們看一下阻止冒泡。

box1.onclick = function (){
    console.log("box1")
}
box2.onclick = function (){
    console.log("box2")
}
box3.onclick = function (e){
    e.stopPropagation();
    console.log("box3")
}

只輸出了box3.
雖然阻止了冒泡但在IE8及以下是不好使的,我們看一下兼容的寫法。

function stopPropagate(e){
    var event = e || window.event;
    if(event.stopPropagation){
        event.stopPropagation();
    }else if(event.cancelBubble){ //IE
        event.cancelBubble = true;
    }
}

阻止默認(rèn)事件兼容

function preventDef(e){
    var g = e || window.event;
    if(g.preventDefault){
        g.preventDefault();
    }else if(g.returnValue){
        g.returnValue = false;
    }
    return false;
}

我們?cè)賮砜纯词录壎ǖ膖his指向

box1.onclick = function (){
    console.log("onclick", this);
}
box1.addEventListener("click",function () {
    console.log("addEventListener", this);
}, false)


IE6、7、8,事件綁定的this指向

box1.attachEvent("onclick",function () {
    console.log("attachEvent", this);
})

attachEvent [object Window]

我們發(fā)現(xiàn),IE6、7、8 this指向window

擴(kuò)展 事件委托

  • 1
  • 2
  • 3

如果我們要監(jiān)聽每一個(gè)li的行為,你會(huì)不會(huì)這么做。

let li = document.getElementsByTagName("li");
for (var i = 0; i < li.length; i++) {
    li.onclick = ()=>{
        console.log(i);
    }
}

評(píng)論區(qū)有位大佬指出了我的錯(cuò)誤,因?yàn)檫@樣形成了閉包,得不到輸出的結(jié)果。因?yàn)楫?dāng)時(shí)只想演示事件委托沒有注意到這個(gè)情況,在此為讀者們表示深深的歉意。下面是更改之后的,之所以不把錯(cuò)誤的修改是想告誡自己還有和我犯同樣錯(cuò)誤的人。

let li = document.getElementsByTagName("li");
//ES6 
for (let i = 0; i < li.length; i++) {
    li[i].onclick = ()=>{
        console.log(i);
    }
}
//IIFE(1)
for (var i = 0; i < li.length; i++) {
    (function(j){
        li[j].onclick = ()=>{
        console.log(j);
    }})(i)
}
//IIFE(2)
for (var i = 0; i < li.length; i++) {
    li[i].onclick = (function(j){
        return ()=>{
            console.log(j);
        }
    })(i);
}

這樣做是對(duì)的單不夠好,要是再加幾個(gè)li或有很多的100|1000個(gè)li你還這樣做是不是感覺就不好了。我們就需要為每一個(gè)li注冊(cè)事件,麻煩不說,注冊(cè)很多事件就不好。那么我們?cè)趺崔k的,使用事件委托,就是把你的事件委托給別人(父級(jí)),利用事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。

我們來看一下。

ul.onclick = function (e){
    console.log(e.target);
}

這就是事件委托。

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

可以大量節(jié)省內(nèi)存占用,減少事件注冊(cè)。

可以實(shí)現(xiàn)當(dāng)新增子對(duì)象時(shí),無需再對(duì)其進(jìn)行事件綁定,對(duì)于動(dòng)態(tài)內(nèi)容部分尤為合適

缺點(diǎn):

事件代理的常用應(yīng)用應(yīng)該僅限于上述需求,如果把所有事件都用事件代理,可能會(huì)出現(xiàn)事件誤判。即本不該被觸發(fā)的事件被綁定上了事件。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100567.html

相關(guān)文章

  • javascript 之 事件

    摘要:處于目標(biāo)階段事件在上發(fā)生并處理。冒泡階段事件又傳播回文檔。不支持捕獲事件的??偨Y(jié)二使用事件委托新添加的元素還會(huì)有之前的事件。事件對(duì)象在觸發(fā)某個(gè)事件時(shí),會(huì)產(chǎn)生一個(gè)事件對(duì)象。 js 是采用異步事件驅(qū)動(dòng)的機(jī)制來響應(yīng)用戶操作的,也就是說當(dāng)用戶對(duì)某個(gè)html元素進(jìn)行操作的時(shí)候,會(huì)產(chǎn)生一個(gè)事件,該事件會(huì)驅(qū)動(dòng)某些函數(shù)來處理。事件源:產(chǎn)生事件的地方(html元素,窗口,其他等等);事件:鼠標(biāo)事件,鍵盤...

    Forest10 評(píng)論0 收藏0
  • JavaScript系列之事件詳解

    摘要:響應(yīng)某個(gè)事件的函數(shù)就叫事件處理程序或事件偵聽器。為事件指定事件處理程序的方法主要有種。事件處理程序事件直接加在元素上。事件委托利用冒泡的原理,把事件加到父元素或祖先元素上,觸發(fā)執(zhí)行效果,解決事件處理程序過多問題。事件委托優(yōu)點(diǎn)提高性能。 JavaScript簡(jiǎn)單入門可以看看我丑丑的Github博客JavaScript簡(jiǎn)單入門 事件 JavaScript與HTML之間的交互是通過事件實(shí)現(xiàn)的...

    pakolagij 評(píng)論0 收藏0
  • js中的事件流和事件處理程序

    摘要:事件流描述的是從頁面中接受事件的順序。事件流中的事件流是事件冒泡流。順序是從外向里級(jí)事件規(guī)定的事件流包括三個(gè)階段事件捕獲階段處于目標(biāo)階段和事件冒泡階段,其中到是處于目標(biāo)階段,如圖所示。添加的事件會(huì)被逆序執(zhí)行。 HTML和js之間的交互是通過事件實(shí)現(xiàn)的。 事件流描述的是從頁面中接受事件的順序。 事件流 IE中的事件流是事件冒泡流。順序是從里向外 eg:div-body-html-...

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

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

0條評(píng)論

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