摘要:源碼源碼行被點擊了點擊了,即委托的事件被點擊了優先添加委托,再添加其他即委托在上的事件數量在下標為的位置插入委托事件解析可以看到,是優先添加委托事件,再添加自身事件,觸發事件的時候也是按這個順序。
前言:
請先回顧下我之前寫的一篇文章:JavaScript之事件委托
一、事件委托(委派)
含義:
在#A上綁定click事件,但是讓#B觸發click事件,相當于在 #B 上假綁定了 click 事件
也就是說:#B 委托了 click 事件給了 #A(在 #A 上綁定)
舉例:
這是A//在父元素上綁定click事件,但只能由子元素觸發父元素上綁定的事件 $("#A").on("click" ,"#B",function (e) { console.log("點擊了B,即B委托A的click事件被點擊了") }) $("#A").on("click" ,"#C",function (e) { console.log(e,"點擊了C,即C委托A的click事件被點擊了") })這是B這是C這是D
二、jQuery 的事件委托順序:
舉例:
(1)A、B、C 各自綁定了click事件
$("#A").on("click" ,function () { console.log("A被點擊了") }) $("#B").on("click" ,function () { console.log("B被點擊了") }) $("#C").on("click",function () { console.log("C被點擊了") })
點擊 C,會依次執行 C、B、A 的click事件
輸出結果:
① C 被點擊了
② B 被點擊了
③ A 被點擊了
(2)A 自己綁定了 click 事件,同時 B、C 還委托給 A 綁定 click 事件
$("#A").on("click" ,function () { console.log("A被點擊了") }) $("#A").on("click" ,"#B",function () { console.log("點擊了B,即B委托A的click事件被點擊了") }) $("#A").on("click" ,"#C",function () { console.log("點擊了C,即C委托A的click事件被點擊了") })
點擊 C,依次執行 C、B 委托給 A 的 click 事件,最后執行 A 自己的 click 事件
輸出結果:
① 點擊了 C,即 C 委托 A 的 click 事件被點擊了
② 點擊了 B,即 B 委托 A 的 click 事件被點擊了
③ A 被點擊了
(3)A 自己綁定了 click 事件,同時 B、C 還委托給 A 綁定 click 事件,同時 B、C 還有自己的 click 事件:
$("#A").on("click" ,function () { console.log("A被點擊了") }) $("#A").on("click" ,"#B",function () { console.log("點擊了B,即B委托A的click事件被點擊了") }) $("#A").on("click" ,"#C",function () { console.log("點擊了C,即C委托A的click事件被點擊了") }) $("#B").on("click" ,function () { console.log("B被點擊了") }) $("#C").on("click",function () { console.log("C被點擊了") })
點擊 C,依次執行:C 自己的事件、B 自己的事件、C 委托給 A 的 click 事件、B委托給 A 的 click 事件、A 自己的 click 事件。
輸出結果:
① C 被點擊了
② B 被點擊了
③ 點擊了 C,即 C 委托 A 的 click 事件被點擊了
④ 點擊了 B,即 B 委托 A 的 click 事件被點擊了
⑤ A 被點擊了
綜上,jQuery事件委托的順序為:
(1)先統一處理自身、父元素自身綁定的事件
(2)再統一處理自身、父元素委托給祖先元素的綁定事件
(3)最后祖先元素處理自身的事件
簡練說,就是:
先處理子元素委托給自身的事件,再處理自身的事件。
源碼:
$().on()—>jQuery.event.add()
jQuery.event = { //源碼5241行 //this, types, fn, data, selector //#A,"click",function(){console.log("A被點擊了")},undefined,undefined //#A,"click",function(){點擊了C,即C委托A的click事件被點擊了},undefined,#C add: function( elem, types, handler, data, selector ) { xxx ... //優先添加委托handler,再添加其他handler // Add to the element"s handler list, delegates in front //delegateCount即委托在#A上的事件數量 if ( selector ) { //在下標為handlers.delegateCount++的位置插入委托事件 handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } }
解析:
可以看到,jQuery 是優先添加委托 click 事件,再添加自身 click 事件,觸發事件的時候也是按這個順序。
注意:
如下的例子,點擊 E 是不能觸發 click 事件的,因為冒泡冒不到 A 上:
這是A這是E$("#A").on("click" ,"#E",function (event) { console.log(event,"點擊了E,即E委托A的click事件被點擊了") })
三、jQuery 綁定事件上的 event 上的 target、currenttarget 和 delegateTarget 的區別?
target 是觸發事件的對象
delegateTarget 是事件委托的原對象
而currenttarget分三種情況:
(1)A 在自身有綁定 click 事件的條件下,C 再去委托 A 綁定 click 事件
這是A$("#A").on("click" ,function (event) { console.log(event,"A被點擊了") }) $("#A").on("click" ,"#C",function (event) { console.log(event,"點擊了C,即C委托A的click事件被點擊了") }) $("#C").on("click",function (event) { console.log(event,"C被點擊了") })這是B這是C這是D
① 點擊了C,即 C 委托 A 的 click 事件被點擊了
event 的結構如下:
可以看到,
target 是 #C,currenttarget 是 #A,delegateTarget 是 #A
也就是說:
target 是觸發 click 事件的對象 #C,currenttarget 是 #C 委托綁定click事件的 #A,并且 #A 自身有綁定 click 事件
② A被點擊了
target 是 #A,currenttarget 是 #A,delegateTarget 是 #A
③ C被點擊了
target 是 #C,currenttarget 是 #C,delegateTarget 是 #C
(2)A 自身沒有綁定 click 事件,C 委托 A 綁定 click 事件
這是A$("#A").on("click" ,"#C",function (event) { console.log(event,"點擊了C,即C委托A的click事件被點擊了") }) $("#C").on("click",function (event) { console.log(event,"C被點擊了") })這是B這是C這是D
① 點擊了 C,即 C 委托 A 的 click 事件被點擊了
event 的結構如下:
可以看到,
target 是 #C,currenttarget 是 #C,而不是 #A,delegateTarget 是 #A
也就是說:
target 是觸發 click 事件的對象 #C,currenttarget 是 #C,因為 #C 委托 #A 綁定 click 事件,并且 #A 自身沒有綁定 click 事件
② C被點擊了
target是 #C,currenttarget 是 #C,delegateTarget 是 #C
(3)A在自身有綁定click事件的條件下,C再去委托A綁定click事件的同時,阻止冒泡!
這是A$("#A").on("click" ,"#C",function (event) { event.stopPropagation() console.log(event,"點擊了C,即C委托A的click事件被點擊了") }) $("#C").on("click",function (event) { console.log(event,"C被點擊了") })這是B這是C這是D
① 點擊了C,即C委托A的click事件被點擊了
event 的結構如下:
可以看到,
target 是 #C,currenttarget 是 #C,而不是 #A,delegateTarget 是 #A
② C 被點擊了
target 是 #C,currenttarget 是 #C,delegateTarget 是 #C
為什么是這樣?
我們來分析下jQuery源碼:
$().on()—>jQuery.event.add()—>elem.addEventListener( type, eventHandle ),eventHandle—>jQuery.event.dispatch
currenttarget在jQuery.event.dispatch中定義,所以我們看jQuery.event.dispatch部分源碼:
jQuery.event = { //源碼5472行 //nativeEvent即原生MouseEvent dispatch: function( nativeEvent ) { //獲取handler隊列 handlerQueue = jQuery.event.handlers.call( this, event, handlers ); //如果沒有阻止冒泡的話,那么 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; } } //源碼5547行 //組裝事件處理隊列 //event是fix過的MouseEvent, handlers handlers: function( event, handlers ) { //目標元素 var cur = event.target; for ( ; cur !== this; cur = cur.parentNode || this ) { if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { matchedHandlers = []; matchedSelectors = {}; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; //sel就是#C // Don"t conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; if ( matchedSelectors[ sel ] === undefined ) { matchedSelectors[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) > -1 : //注意:jQuery.find()和jQuery().find()是不一樣的 jQuery.find( sel, this, null, [ cur ] ).length; } if ( matchedSelectors[ sel ] ) { matchedHandlers.push( handleObj ); } } } if ( matchedHandlers.length ) { handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); } } // Add the remaining (directly-bound) handlers //#A cur = this; //1<2 true //1<1 false //將除委托事件的事件(如自身綁定的事件)放入handlerQueue中 if ( delegateCount < handlers.length ) { handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); } } }
解析:
event.currentTarget—>handlerQueue[ i++ ]—>jQuery.event.handlers
jQuery.event.handlers:
for循環的意思是:
(1)只要cur不等于this,即#A,就一直循環
每次循環:
(2)將matchedHandlers置為[ ]
(3)循環委托綁定的事件數量
循環委托綁定:
(4)matchedHandlers根據handleObj.selector是否有值,pushhandleObj
按照我們的例子來看,當 cur=event.target,cur=#C,然后進入冒泡循環,再進入委托事件循環,
關鍵是:jQuery.find(),
cur=#C 的時候,matchedSelectors[ sel ]=jQuery.find( sel, this, null, [ cur ] ).length=1
但是 cur=#B 的時候(冒泡循環),matchedSelectors[ sel ]=0,也就是說jQuery.find()不同于$().find,它是冒泡找 cur 元素!
所以 matchedHandlers 只 pushlength!==0的委托事件,所以 cur 就是 #C 了(新循環中的當前值)。
然后
cur = this;
cur 又等于 this,即 #A,最后將除委托事件的事件(如自身綁定的事件)放入 handlerQueue 中,cur=#A
再拿例子舉,即(2)A 自身沒有綁定 click 事件,C 委托 A 綁定 click 事件
只有一個 handler,并且是委托 handler,
handlerQueue[ { elem:#C, ... }, ] //#C event.currentTarget = handlerQueue[0].elem
(1)A 在自身有綁定 click 事件的條件下,C 再去委托 A 綁定 click 事件
有兩個 handler
handlerQueue[ { elem:#C, ... }, { elem:#A, ... }, ] //#C event.currentTarget = handlerQueue[0].elem //#A event.currentTarget = handlerQueue[1].elem
因為#A只有一個event,所以在循環handlerQueue[i]時,event.currenttarget最終被#A所覆蓋
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { //最終被#A所覆蓋 event.currentTarget = matched.elem; }
(3)A在自身有綁定click事件的條件下,C再去委托A綁定click事件的同時,阻止冒泡!
因為!event.isPropagationStopped(),所以event.currentTarget=#C,未被#A覆蓋。
(完)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104530.html
摘要:如果你還沒讀過上篇上篇和中篇并無依賴關系,您可以讀過本文之后再閱讀上篇,可戳面試篇寒冬求職季之你必須要懂的原生上小姐姐花了近百個小時才完成這篇文章,篇幅較長,希望大家閱讀時多花點耐心,力求真正的掌握相關知識點。 互聯網寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包,this,原型鏈,就...
摘要:循環可以使用的范圍包括數組和結構某些類似數組的對象對象,以及字符串。只能遍歷數組,不能中斷,返回值是修改后的數組。除了之外,等,也有同樣的問題。聲明一個只讀的常量。這在語法上,稱為暫時性死區。暫時性死區也意味著不再是一個百分百安全的操作。 互聯網寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包...
摘要:只能遍歷數組,不能中斷,返回值是修改后的數組。這在語法上,稱為暫時性死區。作用域鏈無論是還是查詢,都會在當前的作用域開始查找,如果沒有找到,就會向上級作用域繼續查找目標標識符,每次上升一個作用域,一直到全局作用域為止。 互聯網寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包,this,原...
摘要:概念事件委托,通俗來說就是將元素的事件委托給它的父級或者更外級元素處理。級事件規定的事件流包括三個階段事件捕獲目標階段事件冒泡原理事件委托就是利用事件冒泡機制實現的。最適合采用事件委托技術的事件包括和。 概念 事件委托,通俗來說就是將元素的事件委托給它的父級或者更外級元素處理。 事件流 事件流描述的是從頁面中接收事件的順序。 事件冒泡:事件開始由最具體的元素接收,然后逐級向上傳播到較為...
閱讀 1269·2023-04-25 19:10
閱讀 1146·2021-09-10 10:50
閱讀 3034·2021-09-02 15:21
閱讀 1388·2019-08-30 15:52
閱讀 1686·2019-08-30 13:56
閱讀 2090·2019-08-30 12:53
閱讀 1876·2019-08-28 18:22
閱讀 2128·2019-08-26 13:47