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

資訊專欄INFORMATION COLUMN

jQuery源碼解析之你并不真的懂事件委托及target和currenttarget的區(qū)別

khs1994 / 3082人閱讀

摘要:源碼源碼行被點(diǎn)擊了點(diǎn)擊了,即委托的事件被點(diǎn)擊了優(yōu)先添加委托,再添加其他即委托在上的事件數(shù)量在下標(biāo)為的位置插入委托事件解析可以看到,是優(yōu)先添加委托事件,再添加自身事件,觸發(fā)事件的時(shí)候也是按這個(gè)順序。

前言:
請(qǐng)回顧下我之前寫的一篇文章:JavaScript之事件委托

一、事件委托(委派)
含義:
#A上綁定click事件,但是讓#B觸發(fā)click事件,相當(dāng)于在 #B 上假綁定了 click 事件

也就是說:#B 委托了 click 事件給了 #A(在 #A 上綁定)

舉例:

這是A
這是B
這是C
這是D
//在父元素上綁定click事件,但只能由子元素觸發(fā)父元素上綁定的事件 $("#A").on("click" ,"#B",function (e) { console.log("點(diǎn)擊了B,即B委托A的click事件被點(diǎn)擊了") }) $("#A").on("click" ,"#C",function (e) { console.log(e,"點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了") })

二、jQuery 的事件委托順序:

舉例:

(1)A、B、C 各自綁定了click事件

 $("#A").on("click" ,function () {
   console.log("A被點(diǎn)擊了")
 })

 $("#B").on("click" ,function () {
   console.log("B被點(diǎn)擊了")
 })

 $("#C").on("click",function () {
   console.log("C被點(diǎn)擊了")
 })

點(diǎn)擊 C,會(huì)依次執(zhí)行 C、B、A 的click事件

輸出結(jié)果:
① C 被點(diǎn)擊了
② B 被點(diǎn)擊了
③ A 被點(diǎn)擊了

(2)A 自己綁定了 click 事件,同時(shí) B、C 還委托給 A 綁定 click 事件

 $("#A").on("click" ,function () {
   console.log("A被點(diǎn)擊了")
 })

 $("#A").on("click" ,"#B",function () {
   console.log("點(diǎn)擊了B,即B委托A的click事件被點(diǎn)擊了")
 })

 $("#A").on("click" ,"#C",function () {
   console.log("點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了")
 })

點(diǎn)擊 C,依次執(zhí)行 C、B 委托給 A 的 click 事件,最后執(zhí)行 A 自己的 click 事件

輸出結(jié)果:
① 點(diǎn)擊了 C,即 C 委托 A 的 click 事件被點(diǎn)擊了
② 點(diǎn)擊了 B,即 B 委托 A 的 click 事件被點(diǎn)擊了
③ A 被點(diǎn)擊了

(3)A 自己綁定了 click 事件,同時(shí) B、C 還委托給 A 綁定 click 事件,同時(shí) B、C 還有自己的 click 事件:

 $("#A").on("click" ,function () {
   console.log("A被點(diǎn)擊了")
 })

 $("#A").on("click" ,"#B",function () {
   console.log("點(diǎn)擊了B,即B委托A的click事件被點(diǎn)擊了")
 })

 $("#A").on("click" ,"#C",function () {
   console.log("點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了")
 })

 $("#B").on("click" ,function () {
   console.log("B被點(diǎn)擊了")
 })

 $("#C").on("click",function () {
   console.log("C被點(diǎn)擊了")
 })

點(diǎn)擊 C,依次執(zhí)行:C 自己的事件、B 自己的事件、C 委托給 A 的 click 事件、B委托給 A 的 click 事件、A 自己的 click 事件。

輸出結(jié)果:
① C 被點(diǎn)擊了
② B 被點(diǎn)擊了
③ 點(diǎn)擊了 C,即 C 委托 A 的 click 事件被點(diǎn)擊了
④ 點(diǎn)擊了 B,即 B 委托 A 的 click 事件被點(diǎn)擊了
⑤ A 被點(diǎn)擊了

綜上,jQuery事件委托的順序?yàn)椋?/strong>
(1)先統(tǒng)一處理自身、父元素自身綁定的事件
(2)再統(tǒng)一處理自身、父元素委托給祖先元素的綁定事件
(3)最后祖先元素處理自身的事件

簡(jiǎn)練說,就是:
先處理子元素委托給自身的事件,再處理自身的事件。

源碼:
$().on()—>jQuery.event.add()

jQuery.event = {
    //源碼5241行
    //this, types, fn, data, selector

    //#A,"click",function(){console.log("A被點(diǎn)擊了")},undefined,undefined
    //#A,"click",function(){點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了},undefined,#C
    add: function( elem, types, handler, data, selector ) {
      xxx
      ...
      //優(yōu)先添加委托handler,再添加其他handler
      // Add to the element"s handler list, delegates in front
      //delegateCount即委托在#A上的事件數(shù)量
      if ( selector ) {
        //在下標(biāo)為handlers.delegateCount++的位置插入委托事件
        handlers.splice( handlers.delegateCount++, 0, handleObj );
      } else {
        handlers.push( handleObj );
      }
}

解析:
可以看到,jQuery 是優(yōu)先添加委托 click 事件,再添加自身 click 事件,觸發(fā)事件的時(shí)候也是按這個(gè)順序。

注意:
如下的例子,點(diǎn)擊 E 是不能觸發(fā) click 事件的,因?yàn)槊芭菝安坏?A 上:

這是A
這是E
$("#A").on("click" ,"#E",function (event) { console.log(event,"點(diǎn)擊了E,即E委托A的click事件被點(diǎn)擊了") })

三、jQuery 綁定事件上的 event 上的 target、currenttarget 和 delegateTarget 的區(qū)別?

target 是觸發(fā)事件的對(duì)象
delegateTarget 是事件委托的原對(duì)象

而currenttarget分三種情況:
(1)A 在自身有綁定 click 事件的條件下,C 再去委托 A 綁定 click 事件

這是A
這是B
這是C
這是D
$("#A").on("click" ,function (event) { console.log(event,"A被點(diǎn)擊了") }) $("#A").on("click" ,"#C",function (event) { console.log(event,"點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了") }) $("#C").on("click",function (event) { console.log(event,"C被點(diǎn)擊了") })

點(diǎn)擊了C,即 C 委托 A 的 click 事件被點(diǎn)擊了
event 的結(jié)構(gòu)如下:

可以看到,
target 是 #C,currenttarget 是 #A,delegateTarget 是 #A

也就是說:
target 是觸發(fā) click 事件的對(duì)象 #C,currenttarget 是 #C 委托綁定click事件的 #A,并且 #A 自身有綁定 click 事件

② A被點(diǎn)擊了
target 是 #A,currenttarget 是 #A,delegateTarget 是 #A

③ C被點(diǎn)擊了
target 是 #C,currenttarget 是 #C,delegateTarget 是 #C

(2)A 自身沒有綁定 click 事件,C 委托 A 綁定 click 事件

這是A
這是B
這是C
這是D
$("#A").on("click" ,"#C",function (event) { console.log(event,"點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了") }) $("#C").on("click",function (event) { console.log(event,"C被點(diǎn)擊了") })

點(diǎn)擊了 C,即 C 委托 A 的 click 事件被點(diǎn)擊了
event 的結(jié)構(gòu)如下:

可以看到,
target 是 #C,currenttarget 是 #C,而不是 #A,delegateTarget 是 #A

也就是說:
target 是觸發(fā) click 事件的對(duì)象 #C,currenttarget 是 #C,因?yàn)?#C 委托 #A 綁定 click 事件,并且 #A 自身沒有綁定 click 事件

② C被點(diǎn)擊了
target是 #C,currenttarget 是 #C,delegateTarget 是 #C

(3)A在自身有綁定click事件的條件下,C再去委托A綁定click事件的同時(shí),阻止冒泡!

這是A
這是B
這是C
這是D
$("#A").on("click" ,"#C",function (event) { event.stopPropagation() console.log(event,"點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了") }) $("#C").on("click",function (event) { console.log(event,"C被點(diǎn)擊了") })

點(diǎn)擊了C,即C委托A的click事件被點(diǎn)擊了
event 的結(jié)構(gòu)如下:

可以看到,
target 是 #C,currenttarget 是 #C,而不是 #A,delegateTarget 是 #A

② C 被點(diǎn)擊了
target 是 #C,currenttarget 是 #C,delegateTarget 是 #C

為什么是這樣?
我們來(lái)分析下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隊(duì)列
    handlerQueue = jQuery.event.handlers.call( this, event, handlers );

    //如果沒有阻止冒泡的話,那么
    while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
        event.currentTarget = matched.elem;
    }
  }
  
    //源碼5547行
    //組裝事件處理隊(duì)列  
    //event是fix過的MouseEvent, handlers  
    handlers: function( event, handlers ) {
      //目標(biāo)元素
      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循環(huán)的意思是:
(1)只要cur不等于this,即#A,就一直循環(huán)
每次循環(huán):
(2)將matchedHandlers置為[ ]
(3)循環(huán)委托綁定的事件數(shù)量
循環(huán)委托綁定:
(4)matchedHandlers根據(jù)handleObj.selector是否有值,pushhandleObj

按照我們的例子來(lái)看,當(dāng) cur=event.target,cur=#C,然后進(jìn)入冒泡循環(huán),再進(jìn)入委托事件循環(huán),
關(guān)鍵是:jQuery.find()
cur=#C 的時(shí)候,matchedSelectors[ sel ]=jQuery.find( sel, this, null, [ cur ] ).length=1
但是 cur=#B 的時(shí)候(冒泡循環(huán)),matchedSelectors[ sel ]=0,也就是說jQuery.find()不同于$().find,它是冒泡找 cur 元素!

所以 matchedHandlers 只 pushlength!==0的委托事件,所以 cur 就是 #C 了(新循環(huán)中的當(dāng)前值)。

然后

cur = this;

cur 又等于 this,即 #A,最后將除委托事件的事件(如自身綁定的事件)放入 handlerQueue 中,cur=#A

再拿例子舉,即(2)A 自身沒有綁定 click 事件,C 委托 A 綁定 click 事件
只有一個(gè) handler,并且是委托 handler,

handlerQueue[
  {
    elem:#C,
    ...
  },
]
//#C
event.currentTarget = handlerQueue[0].elem

(1)A 在自身有綁定 click 事件的條件下,C 再去委托 A 綁定 click 事件
有兩個(gè) handler

handlerQueue[
  {
    elem:#C,
    ...
  },
  {
    elem:#A,
    ...
  },
]
//#C
event.currentTarget = handlerQueue[0].elem
//#A
event.currentTarget = handlerQueue[1].elem

因?yàn)?b>#A只有一個(gè)event,所以在循環(huán)handlerQueue[i]時(shí),event.currenttarget最終被#A所覆蓋

 while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
        //最終被#A所覆蓋
        event.currentTarget = matched.elem;
    }

(3)A在自身有綁定click事件的條件下,C再去委托A綁定click事件的同時(shí),阻止冒泡!
因?yàn)?b>!event.isPropagationStopped(),所以event.currentTarget=#C,未被#A覆蓋。

(完)

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

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

相關(guān)文章

  • 【面試篇】寒冬求職季之你必須要原生JS(中)

    摘要:如果你還沒讀過上篇上篇和中篇并無(wú)依賴關(guān)系,您可以讀過本文之后再閱讀上篇,可戳面試篇寒冬求職季之你必須要懂的原生上小姐姐花了近百個(gè)小時(shí)才完成這篇文章,篇幅較長(zhǎng),希望大家閱讀時(shí)多花點(diǎn)耐心,力求真正的掌握相關(guān)知識(shí)點(diǎn)。 互聯(lián)網(wǎng)寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環(huán)境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包,this,原型鏈,就...

    Mike617 評(píng)論0 收藏0
  • 【面試篇】寒冬求職季之你必須要原生JS(上)

    摘要:循環(huán)可以使用的范圍包括數(shù)組和結(jié)構(gòu)某些類似數(shù)組的對(duì)象對(duì)象,以及字符串。只能遍歷數(shù)組,不能中斷,返回值是修改后的數(shù)組。除了之外,等,也有同樣的問題。聲明一個(gè)只讀的常量。這在語(yǔ)法上,稱為暫時(shí)性死區(qū)。暫時(shí)性死區(qū)也意味著不再是一個(gè)百分百安全的操作。 互聯(lián)網(wǎng)寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環(huán)境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包...

    AlphaWatch 評(píng)論0 收藏0
  • 【面試篇】寒冬求職季之你必須要原生JS(上)

    摘要:只能遍歷數(shù)組,不能中斷,返回值是修改后的數(shù)組。這在語(yǔ)法上,稱為暫時(shí)性死區(qū)。作用域鏈無(wú)論是還是查詢,都會(huì)在當(dāng)前的作用域開始查找,如果沒有找到,就會(huì)向上級(jí)作用域繼續(xù)查找目標(biāo)標(biāo)識(shí)符,每次上升一個(gè)作用域,一直到全局作用域?yàn)橹埂? 互聯(lián)網(wǎng)寒冬之際,各大公司都縮減了HC,甚至是采取了裁員措施,在這樣的大環(huán)境之下,想要獲得一份更好的工作,必然需要付出更多的努力。 一年前,也許你搞清楚閉包,this,原...

    寵來(lái)也 評(píng)論0 收藏0
  • JavaScript事件委托原理

    摘要:概念事件委托,通俗來(lái)說就是將元素的事件委托給它的父級(jí)或者更外級(jí)元素處理。級(jí)事件規(guī)定的事件流包括三個(gè)階段事件捕獲目標(biāo)階段事件冒泡原理事件委托就是利用事件冒泡機(jī)制實(shí)現(xiàn)的。最適合采用事件委托技術(shù)的事件包括和。 概念 事件委托,通俗來(lái)說就是將元素的事件委托給它的父級(jí)或者更外級(jí)元素處理。 事件流 事件流描述的是從頁(yè)面中接收事件的順序。 事件冒泡:事件開始由最具體的元素接收,然后逐級(jí)向上傳播到較為...

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

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

0條評(píng)論

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