摘要:那什么是事件冒泡呢概念請自行百度,直接上圖。,不支持事件捕獲只支持事件冒泡。即本不該被觸發(fā)的事件被綁定上了事件。
在上一篇《JS知識點大雜燴》中說到了事件流但沒有詳細的介紹,這篇文章就來介紹一下事件流。
事件流一共由三個階段分別是:
1.捕獲階段 2.目標階段 3.冒泡階段
事件綁定大家都知道,有DOM0級(on+type)和DOM2級(addEventListener),我覺得說那么多概念不好理解,直接看代碼吧,為了方便我就直接使用id來獲取元素。
DOM0級
box1.onclick = function(){ console.log("box1"); }
輸出了box1這個我們都知道,再來看一下。
box1.onclick = function(){ console.log("box1"); } box1.onclick = function(){ console.log("box1 two"); }
輸出了box1 two,因為DOM0級會覆蓋掉之前在同一元素上面的綁定,再來看一下。
box1.onclick = function(){ console.log("box1"); } box2.onclick = function(){ console.log("box2"); } box3.onclick = function(){ console.log("box3"); }
當我們點擊box1時都知道輸出box1,可是當我們點擊box3時彈出什么呢?
你可能會感覺奇怪,為什么我點擊的box3怎么其他的也會觸發(fā)?因為事件冒泡。那什么是事件冒泡呢?概念請自行百度,直接上圖。
這就叫做事件冒泡,一級一級往上冒直到window這里我沒有畫出來。DOM0級只支持冒泡階段。
DOM2級
box1.addEventListener("click", function(){ console.log("box1"); },false); box2.addEventListener("click", function(){ console.log("box2"); },false); box3.addEventListener("click", function(){ console.log("box3"); },false);
輸出跟上面是一樣的,因為我們綁定在了冒泡階段。(true捕獲,false冒泡)。
我們再來看看捕獲階段是怎么樣的
box1.addEventListener("click", function(){ console.log("box1"); },true); box2.addEventListener("click", function(){ console.log("box2"); },true); box3.addEventListener("click", function(){ console.log("box3"); },true);
我們點擊box3看到
你可能會發(fā)現(xiàn)順序反過來了,那這是為什么呢?因為事件捕獲,那什么是時間捕獲呢?概念請自行百度,直接上圖。
這就是捕獲階段,跟冒泡階段完全相反。
那冒泡跟捕獲的執(zhí)行順序是什么樣的呢?我分別在每一個元素上綁定了兩個階段的同一事件,我們來看看觸發(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);
我們點擊box3看到,先捕獲后冒泡。
那是不是都這樣呢?我們稍微改動一下。
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)反過來了,其實這就叫做目標階段吧。在你觸發(fā)事件的目標元素身上不區(qū)分冒泡捕獲,按綁定的順序來執(zhí)行。
我們用圖來看一下。
這樣是不是太簡單我們來一點復雜的。
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ā)順序是什么樣的?(我覺得你最好先自己把答案寫出來)
看看你答對了沒有
這樣會不會太簡單,換一下順序
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);
答對了嗎?
再說一下冒泡和捕獲
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);
你說這樣點擊會輸出什么?你是不是猶豫了?說明你還是不懂冒泡和捕獲。
不要讓你看到的騙了你,冒泡是DOM結構的父子關系而不是看起來是不是包裹的關系。(答案同上面)。
忘了IE了,說一下IE的事件機制。
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") })
這個會輸出什么?(提示:不會覆蓋)
答案是:box1 box2 box3
哈哈,開玩笑啊。
是不是很奇怪,IE中該事件是先綁定的后輸出。IE6、7、8,不支持事件捕獲只支持事件冒泡。
阻止事件冒泡兼容
我們先來說一下不支持冒泡的事件:blur、focus、mouseenter、mouseleave。(我就知道這些)
還是這個例子,我們看一下阻止冒泡。
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; } }
阻止默認事件兼容
function preventDef(e){ var g = e || window.event; if(g.preventDefault){ g.preventDefault(); }else if(g.returnValue){ g.returnValue = false; } return false; }
我們再來看看事件綁定的this指向
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
擴展 事件委托
如果我們要監(jiān)聽每一個li的行為,你會不會這么做。
let li = document.getElementsByTagName("li"); for (var i = 0; i < li.length; i++) { li.onclick = ()=>{ console.log(i); } }
評論區(qū)有位大佬指出了我的錯誤,因為這樣形成了閉包,得不到輸出的結果。因為當時只想演示事件委托沒有注意到這個情況,在此為讀者們表示深深的歉意。下面是更改之后的,之所以不把錯誤的修改是想告誡自己還有和我犯同樣錯誤的人。
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); }
這樣做是對的單不夠好,要是再加幾個li或有很多的100|1000個li你還這樣做是不是感覺就不好了。我們就需要為每一個li注冊事件,麻煩不說,注冊很多事件就不好。那么我們怎么辦的,使用事件委托,就是把你的事件委托給別人(父級),利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。
我們來看一下。
ul.onclick = function (e){ console.log(e.target); }
這就是事件委托。
優(yōu)點:
可以大量節(jié)省內(nèi)存占用,減少事件注冊。
可以實現(xiàn)當新增子對象時,無需再對其進行事件綁定,對于動態(tài)內(nèi)容部分尤為合適
缺點:
事件代理的常用應用應該僅限于上述需求,如果把所有事件都用事件代理,可能會出現(xiàn)事件誤判。即本不該被觸發(fā)的事件被綁定上了事件。
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/100567.html
摘要:處于目標階段事件在上發(fā)生并處理。冒泡階段事件又傳播回文檔。不支持捕獲事件的。總結二使用事件委托新添加的元素還會有之前的事件。事件對象在觸發(fā)某個事件時,會產(chǎn)生一個事件對象。 js 是采用異步事件驅(qū)動的機制來響應用戶操作的,也就是說當用戶對某個html元素進行操作的時候,會產(chǎn)生一個事件,該事件會驅(qū)動某些函數(shù)來處理。事件源:產(chǎn)生事件的地方(html元素,窗口,其他等等);事件:鼠標事件,鍵盤...
摘要:響應某個事件的函數(shù)就叫事件處理程序或事件偵聽器。為事件指定事件處理程序的方法主要有種。事件處理程序事件直接加在元素上。事件委托利用冒泡的原理,把事件加到父元素或祖先元素上,觸發(fā)執(zhí)行效果,解決事件處理程序過多問題。事件委托優(yōu)點提高性能。 JavaScript簡單入門可以看看我丑丑的Github博客JavaScript簡單入門 事件 JavaScript與HTML之間的交互是通過事件實現(xiàn)的...
摘要:事件流描述的是從頁面中接受事件的順序。事件流中的事件流是事件冒泡流。順序是從外向里級事件規(guī)定的事件流包括三個階段事件捕獲階段處于目標階段和事件冒泡階段,其中到是處于目標階段,如圖所示。添加的事件會被逆序執(zhí)行。 HTML和js之間的交互是通過事件實現(xiàn)的。 事件流描述的是從頁面中接受事件的順序。 事件流 IE中的事件流是事件冒泡流。順序是從里向外 eg:div-body-html-...
閱讀 3326·2021-11-19 11:36
閱讀 2927·2021-09-27 13:34
閱讀 1990·2021-09-22 15:17
閱讀 2404·2019-08-30 13:49
閱讀 754·2019-08-26 13:58
閱讀 1359·2019-08-26 10:47
閱讀 2538·2019-08-23 18:05
閱讀 600·2019-08-23 14:25