click事件在什么时候出发_超全的js事件机制amp;事件委托
超全的js事件機制&事件委托,想要理解js事件只需認真看完此篇即可~
目錄結構:
什么是事件機制
事件冒泡事件捕獲
DOM事件流事件委托
誤區
在同一個對象上注冊事件,并不一定按照注冊順序執行
event.stopPropagation();就是阻止事件的冒泡return false;阻止默認行為
拓展
stopImmediatePropagation 的使用setCapture 和 releaseCapture
參考文章
什么是事件機制
JavaScript 事件機制描述的是事件在 DOM 里面的傳遞順序,以及我們可以對這些事件做出如何的響應。
DOM事件流(event flow )存在三個階段:事件捕獲階段、處于目標階段、事件冒泡階段。
事件捕獲(event capturing): 通俗的理解就是,當鼠標點擊或者觸發dom事件時,瀏覽器會從根節點開始由外到內進行事件傳播,即點擊了子元素,如果父元素通過事件捕獲方式注冊了對應的事件的話,會先觸發父元素綁定的事件。
事件冒泡(dubbed bubbling): 與事件捕獲恰恰相反,事件冒泡順序是由內到外進行事件傳播,直到根節點。無論是事件捕獲還是事件冒泡,它們都有一個共同的行為,就是事件傳播,它就像一跟引線,只有通過引線才能將綁在引線上的鞭炮(事件監聽器)引爆, 試想一下,如果引線不導火了,那鞭炮就只有一響了!!!
dom標準事件流的觸發的先后順序為 :先捕獲再冒泡,即當觸發dom事件時,會先進行事件捕獲,捕獲到事件源之后通過事件傳播進行事件冒泡。
不同的瀏覽器對此有著不同的實現,IE10及以下不支持捕獲型事件,所以就少了一個事件捕獲階段,IE11、Chrome 、Firefox、Safari等瀏覽器則同時存在。
說到事件冒泡與捕獲就不得不提一下兩個用于事件綁定的方法addEventListener 、
attachEvent 。當然還有其它的事件綁定的方式這里不做介紹。
addEventListener(event, listener, useCapture)
·參數定義:event---(事件名稱,如click,不帶on), listener---事件監聽函數,
useCapture---是否采用事件捕獲進行事件捕捉, 默認為false,即采用事件冒泡方式
addEventListener在 IE11、Chrome 、Firefox、Safari等瀏覽器都得到支持。
attachEvent(event,listener)
·參數定義:event---(事件名稱,如onclick,帶on), listener---事件監聽函數。
attachEvent主要用于IE瀏覽器,并且僅在IE10及以下才支持,IE11已經廢了這個方法了
(微軟還是挺識趣的,慢慢向標準靠攏)。
事件冒泡
事件開始時由最具體的元素接受,然后逐級向上傳播到較為不具體的元素
<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件機制</title> <style> #parent{ width: 200px; height:200px; text-align: center; line-height: 3;background: green; } #child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child");document.body.addEventListener("click",function(e){ console.log("click-body"); },false);parent.addEventListener("click",function(e){ console.log("click-parent"); },false);child.addEventListener("click",function(e){ console.log("click-child"); },false); </script> </body> </html>通過"addEventListener"方法,采用事件冒泡方式給dom元素注冊click事件,點擊子元素會發生什么呢?如果你對事件冒泡有一定了解的話那你肯定知道上面的代碼會輸出的順
序,沒錯,如下圖所示:
事件觸發順序是由內到外的,這就是事件冒泡,雖然只點擊子元素,但是它的父元素也會觸發相應的事件,其實這是合理的,因為子元素在父元素里面,點擊子元素也就相當于變相的點擊了父元素,這樣理解對吧?這里有同學可能要問了,如果點擊子元素不想觸發父元素的事件怎么辦?肯定可以的,那就是停止事件傳播---event.stopPropagation();
事件捕獲
不太具體的節點更早接受事件,而最具體的元素最后接受事件,和事件冒泡相反修改上面栗子中的代碼,給parent元素注冊一個捕獲事件,如下
var parent = document.getElementById("parent"); var child = document.getElementById("child");document.body.addEventListener("click",function(e){ console.log("click-body"); },false);parent.addEventListener("click",function(e){ console.log("click-parent---事件傳播"); },false); //新增事件捕獲事件代碼 parent.addEventListener("click",function(e){ console.log("click-parent--事件捕獲"); },true); child.addEventListener("click",function(e){ console.log("click-child"); },false);如果你看明白了我前面說的那些,你就知道這個栗子的輸出順序了。
父元素通過事件捕獲的方式注冊了click事件,所以在事件捕獲階段就會觸發,然后到了目標階段,即事件源,之后進行事件傳播,parent同時也用冒泡方式注冊了click事件,所以這里會觸發冒泡事件,最后到根節點。這就是整個事件流程。
DOM事件流
DOM2級事件規定事件流包括三個階段,事件捕獲階段,處于目標階段,時間冒泡階段, 首先發生的是事件捕獲,為截取事件提供機會,然后是實際目標接受事件,最后是冒泡階段
注:Opera、Firefox、Sarfari都支持DOM事件流,IE不支持事件流,只支持時間冒泡
當一個事件發生以后,它會在不同的DOM節點之間傳播(propagation)。這種傳播分為三個階段:
第一階段:從window對象傳導到目標節點,稱為“捕獲階段”(capture phase)。第二階段:在目標節點上觸發,稱為“目標階段”(target phase)。
第三階段:從目標節點傳導回window對象,稱為“冒泡階段”(bubbling phase)。
事件委托
事件委托其實也叫事件代理。
定義:事件代理就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。(delegation)。
var ul = document.querySelector('ul'); ul.addEventListener('click', function(event){ if(event.target.tagName.toLowerCase() === 'li'){ //... }})上面代碼的click 事件的監聽函數定義在<ul> 節點,但是實際上,它處理額是子節點<li> 的click事件。這樣的好處是,只要定義一個監聽函數,就能處理多個子節點的事件,且以后再添加子節點,監聽函數依然有效。
那什么樣的事件可以用事件委托,什么樣的事件不可以用呢?
適合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress 。值得注意的是,mouseover 和mouseout 雖然也有事件冒泡,但是處理它們的時候需要特別的注意,因為需要經常計算它們的位置,處理起來不太容易。
不適合的就有很多了,舉個例子,mousemove,每次都要計算它的位置,非常不好把控,在不如說focus,blur之類的,本身就沒用冒泡的特性,自然就不能用事件委托了。
更加詳細內容可查看:Js 中事件綁定、事件代理和事件委托
誤區
在同一個對象上注冊事件,并不一定按照注冊順序執行
之所以如此是因為事件目的地節點既綁定了冒泡事件也綁定了捕獲事件,此時的執行順序按照綁定的先后順序執行(情況比較少見)。
舉例
<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件機制</title> <style> #parent{ width: 200px; height:200px; text-align: center; line-height: 3; background: green; }#child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child");// document.body.addEventListener("click",function(e){ // console.log("click-body"); // },false); child.addEventListener("click",function(e){ console.log("click-child"); },false);child.addEventListener("click",function(e){ console.log("click-child-捕獲"); },true); parent.addEventListener("click",function(e){ console.log("click-parent"); },false);parent.addEventListener("click",function(e){ console.log("click-parent-捕獲"); },true);</script> </body> </html>點擊子DIV執行結果:
交換子div事件,如下:
<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件機制</title> <style> #parent{ width: 200px; height:200px; text-align: center; line-height: 3; background: green; } #child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child");// document.body.addEventListener("click",function(e){ // console.log("click-body"); // },false);child.addEventListener("click",function(e){ console.log("click-child-捕獲");},true); child.addEventListener("click",function(e){ console.log("click-child"); },false);parent.addEventListener("click",function(e){ console.log("click-parent"); },false);parent.addEventListener("click",function(e){ console.log("click-parent-捕獲"); },true);</script> </body> </html>點擊子DIV執行結果:
由于子DIV上綁定了捕獲和冒泡事件,所以此時的執行順序是按照綁定的執行順序。實際這種情況很少。
event.stopPropagation();就是阻止事件的冒泡
這個表述不能說他錯誤,但是是不完整的,他除了阻止事件的冒泡,還阻止事件的繼續捕獲,簡而言之就是阻止事件的進一步傳播 。下面的例子可以看到:
<html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>js事件機制</title> <style>#parent{ width: 200px; height:200px; text-align: center; line-height: 3; background: green; } #child{ width: 100px; height: 100px; margin: 0 auto; background: orange; } </style> </head> <body> <div id="parent"> 父元素 <div id="child"> 子元素 </div> </div> <script type="text/javascript"> var parent = document.getElementById("parent"); var child = document.getElementById("child");child.addEventListener("click",function(e){ console.log("click-child-捕獲"); },true); // child.addEventListener("click",function(e){ // console.log("click-child"); // },false);// parent.addEventListener("click",function(e){ // console.log("click-parent"); // },false);parent.addEventListener("click",function(e){ event.stopPropagation(); console.log("click-parent-捕獲"); },true);</script> </body> </html>執行結果:
return false;阻止默認行為
return false;事件處理過程中,阻止了事件冒泡,也阻止了默認行為(比如剛才它就沒有執行超鏈接的跳轉)
return false 不僅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 則只阻止事件的進一步傳播,不阻止事件本身。
拓展
stopImmediatePropagation 的使用
這玩意兒是 w3c 的東西,使用的也不是特別多,我們知道 stopPropagation 可以阻止事件的進一步傳播,但是他阻止不了該元素上綁定的其他函數的執行,比如我們在 obj 上綁定了 func1 和 func2,如果我們在 func1 中使用了 stopPropagation ,那 func2 依然還是會執行出來。倘若這里使用 stopImmediatePropagation,結果就不一樣了,他不僅阻止事件的傳播,還阻止 func2 的執行。如:
結果是:
而改成evt.stopImmediatePropagation();之后,阻止了第二個監聽事件的觸發:
結果是:
setCapture 和 releaseCapture
這兩個是 IE 下的事件綁定函數,只要我們在某個元素上 setCapture 了,那么你在任何地方的鼠標操作(mouseXXX之類的動作)都會在這個元素上觸發(前提是你在這個元素上綁定了事件),releaseCapture 或者本窗口失去聚焦才會釋放這個綁定~
參考文章
JavaScript 詳說事件機制之冒泡、捕獲、傳播、委托[解惑]JavaScript事件機制
DOM事件傳播機制 js中的事件委托或事件代理詳解
總結
以上是生活随笔為你收集整理的click事件在什么时候出发_超全的js事件机制amp;事件委托的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hadoop Hive概念学习系列之hi
- 下一篇: “光伏进社区” 应及早谋划布局