国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

jQuery源碼解析之jQuery.event.dispatch()

GraphQuery / 1551人閱讀

摘要:一起源方法最終是用綁定事件的而方法正是等于二作用觸發綁定的事件的處理程序源碼源碼行即原生觸發事件的處理程序修正對象獲取事件的處理程序集合,結構如下從數據緩存中獲取事件處理集合即目標元素委托目標這段代碼壓根不會執行,因為全局搜索沒找到結構

一、起源
jQuery.event.add()方法最終是用addEventListener綁定事件的:

elem.addEventListener( type, eventHandle )

eventHandle方法正是等于jQuery.event.dispatch()

  if ( !( eventHandle = elemData.handle ) ) {
        eventHandle = elemData.handle = function( e ) {
          return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
            jQuery.event.dispatch.apply( elem, arguments ) : undefined;
        };
   }

二、$.event.dispatch()
作用:
觸發綁定的事件的處理程序

源碼:

    //源碼5472行
    //nativeEvent即原生MouseEvent
    //觸發事件的處理程序
    dispatch: function( nativeEvent ) {
      //修正event對象
      // Make a writable jQuery.Event from the native event object
      var event = jQuery.event.fix( nativeEvent );
      console.log(event,"event5479")
      
      var i, j, ret, matched, handleObj, handlerQueue,
        args = new Array( arguments.length ),
        //獲取click事件的處理程序集合,結構如下:
        //[
        // {type: "click", origType: "click", data: undefined, handler: ?, guid: 1},
        // {type: "click", origType: "click", data: undefined, handler: ?, guid: 2},
        // delegateCount:0,
        //]
        //從數據緩存中獲取事件處理集合
        handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
        //click:{
        // trigger:{},
        // _default:{}
        //}
        special = jQuery.event.special[ event.type ] || {};
      // Use the fix-ed jQuery.Event rather than the (read-only) native event
      args[ 0 ] = event;

      for ( i = 1; i < arguments.length; i++ ) {
        args[ i ] = arguments[ i ];
      }
      //this即目標元素
      //delegateTarget:委托目標
      event.delegateTarget = this;
      //這段代碼壓根不會執行,因為全局搜索沒找到preDispatch
      // Call the preDispatch hook for the mapped type, and let it bail if desired
      if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
        return;
      }
      // Determine handlers
      //結構如下
      //[{
      // elem:xx,
      // handlers:[
      //  {type: "click", origType: "click", data: undefined, handler: ?, guid: 1},
      //  {type: "click", origType: "click", data: undefined, handler: ?, guid: 2},
      //  ]
      //}]
      //獲取handler隊列
      handlerQueue = jQuery.event.handlers.call( this, event, handlers );
      // Run delegates first; they may want to stop propagation beneath us
      i = 0;
      //沒有執行stopPropagation()的話
      console.log(handlerQueue,"handlerQueue5525")
      //先判斷有沒有冒泡
      //再判斷有沒有阻止剩下的handler執行
      while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
        console.log(matched,"matched5542")
        event.currentTarget = matched.elem;

        j = 0;
        //handleObj即單個事件處理程序
        //沒有執行stopImmediatePropagation()的話

        //依次執行每一個handler
        while ( ( handleObj = matched.handlers[ j++ ] ) &&
        !event.isImmediatePropagationStopped() ) {

          // Triggered event must either 1) have no namespace, or 2) have namespace(s)
          // a subset or equal to those in the bound event (both can have no namespace).
          if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
            //通過循環將為event添加handleObj和handleObj.data
            event.handleObj = handleObj;
            event.data = handleObj.data;
            //關鍵代碼,執行事件處理程序handler
            ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
              handleObj.handler ).apply( matched.elem, args );
            if ( ret !== undefined ) {
              //event.result賦值ret
              if ( ( event.result = ret ) === false ) {
                //阻止默認行為
                event.preventDefault();
                //阻止冒泡
                event.stopPropagation();
              }
            }
          }
        }
      }

      // Call the postDispatch hook for the mapped type
      if ( special.postDispatch ) {
        special.postDispatch.call( this, event );
      }
      console.log(handlers,"event5587")
      //undefined
      return event.result;
    },

解析:

(1)jQuery.event.fix()
作用:
將原生事件對象MouseEvent修正(fix)成jQueryevent對象

源碼:

    //源碼5700行
    fix: function( originalEvent ) {
      //如果存在屬性id則原樣返回(因為已處理成jQueryEvent)
      return originalEvent[ jQuery.expando ] ?
        originalEvent :
        new jQuery.Event( originalEvent );
    },

解析:
可以看到fix的本質是新建一個event對象,再看jQuery.Event()方法

(2)jQuery.Event()
源碼:

 //click,false
  //修正event對象
  //源碼5777行
  //src即MouseEvent
  jQuery.Event = function( src, props ) {

    // Allow instantiation without the "new" keyword
    if ( !( this instanceof jQuery.Event ) ) {
      return new jQuery.Event( src, props );
    }

    // Event object
    //src.type=click
    if ( src && src.type ) {
      //MouseEvent
      this.originalEvent = src;
      //click
      this.type = src.type;

      // Events bubbling up the document may have been marked as prevented
      // by a handler lower down the tree; reflect the correct value.
      this.isDefaultPrevented = src.defaultPrevented ||
      src.defaultPrevented === undefined &&

      // Support: Android <=2.3 only
      src.returnValue === false ?
        returnTrue :
        returnFalse;

      // Create target properties
      // Support: Safari <=6 - 7 only
      // Target should not be a text node (#504, #13143)
      this.target = ( src.target && src.target.nodeType === 3 ) ?
        src.target.parentNode :
        src.target;

      this.currentTarget = src.currentTarget;
      this.relatedTarget = src.relatedTarget;

      // Event type
    } else {
      //click
      this.type = src;
    }

    // Put explicitly provided properties onto the event object
    //false
    if ( props ) {
      jQuery.extend( this, props );
    }

    // Create a timestamp if incoming event doesn"t have one
    this.timeStamp = src && src.timeStamp || Date.now();

    // Mark it as fixed
    //修正的標志
    this[ jQuery.expando ] = true;
  };

解析:
簡單來說,就是把原生event事件上的常用屬性賦值到了jQueryevent

  $("#A").on("click" ,function (event) {
    //這個就是jQuery.Event()構建出的event
    console.log(event,"A被點擊了")
  })

jQueryevent結構如下:

//click的event就是jQuery.Event
jQuery.Event{
  handleObj{
    data:undefined,
    guid: 2,
    handler:function(){console.log("A被點擊了")},
    namespace: "clickA",
    origType: "click",
    selector: "#B",
    type: "click.clickA",
  },
  originalEvent:{
    //就是MouseEvent
  },
  target:div#B,
  type: "click",
  delegateTarget: div#A,
  //fix 的標志
  jQuery331087940272164138: true,
  currentTarget: div#A,
  isDefaultPrevented:xxx,
  timeStamp:Date.now(),
  isDefaultPrevented:function(){return false}
}

注意下originalEvent jQuery.extend( this, props )
前者就是原生MouseEvent,只是將原生event作為jQuery.event的originalEvent屬性了;
后者是擴展屬性,如果開發者想額外加入自定義屬性的話。

(3)dataPriv.get( this, "events" )
注意:
jQuery的數據緩存里的events和上面說的event是不同的

數據緩存的events是用來結構如下:

{
  click:[
    {
      type: "click", 
      origType: "click", 
      data: undefined, 
      handler: function(){console.log("B委托A綁定click事件")}, 
      guid: 1,
      namespace: "",
      needsContext: undefined,
      selector: #B,
    },
    {
      type: "click", 
      origType: "click", 
      data: undefined, 
      handler: function(){console.log("A綁定click事件")}, 
      guid: 2,
      namespace: "",
      needsContext: undefined,
      selector: undefined,
    },
    //事件委托的數量
    delegateCount:1,
  ],
  focus:[
    {
      type: "focus", 
      origType: "focus", 
      data: undefined, 
      handler: function(){console.log("A綁定focus事件")}, 
      guid: 3,
      namespace: "",
      needsContext: undefined,
      selector: undefined,
    },
     delegateCount:0,
  ],
}

(4) jQuery.event.handlers
作用:
獲取handler隊列

源碼:

jQuery.event = {
    //源碼5547行
    //組裝事件處理隊列  
    //event是fix過的MouseEvent, handlers  
    handlers: function( event, handlers ) {
      var i, handleObj, sel, matchedHandlers, matchedSelectors,
        handlerQueue = [],
        //0
        delegateCount = handlers.delegateCount,
        //目標元素
        cur = event.target;
      //handlers,第一個handler是委托事件,第二個handler是自身事件
      // Find delegate handlers
      if ( delegateCount &&

        // Support: IE <=9
        // Black-hole SVG  instance trees (trac-13180)
        cur.nodeType &&

        // Support: Firefox <=42
        // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
        // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
        // Support: IE 11 only
        // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
        !( event.type === "click" && event.button >= 1 ) ) {
        //循環,event.target冒泡到cur.parentNode,
        //直至綁定的目標元素#A,退出循環
        for ( ; cur !== this; cur = cur.parentNode || this ) {
          console.log(cur,"cur5618")
          // Don"t check non-elements (#13208)
          // Don"t process clicks on disabled elements (#6911, #8165, #11382, #11764)
          if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {

            matchedHandlers = [];
            matchedSelectors = {};
            //在每一層,依次將委托的事件push進matchedHandlers
            //順序由下到上
            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 );
              }
            }
            //然后將該層委托事件的數組放進handlers中
            //handlerQueue是所有層委托事件的集合
            if ( matchedHandlers.length ) {
              handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
            }
          }
        }
      }

      // Add the remaining (directly-bound) handlers
      //最終冒泡到this元素
      cur = this;
      //1<2
      //將除委托事件的事件(如自身綁定的事件)放入handlerQueue中
      if ( delegateCount < handlers.length ) {
        handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
      }
      //[{
      // elem:xx,
      // handlers:[
      //  {type: "click", origType: "click", data: undefined, handler: ?, guid: 1},
      //  {type: "click", origType: "click", data: undefined, handler: ?, guid: 2},
      //  ]
      //}]
      return handlerQueue;
    },

}

解析:
注意下這個雙層循環,目的是把每一層的委托事件的集合pushmatchedHandlers,然后再將matchedHandlers放進handlerQueue隊列

在處理完每層的委托事件后,將剩下的自身綁定事件再pushhandlerQueue隊列中

也就是說,handlerQueue的結構如下:

[
//委托事件
  {
   elem:xx,
   handlers:[
      {type: "click", origType: "click", data: undefined, handler: ?, guid: 1},
      {type: "click", origType: "click", data: undefined, handler: ?, guid: 2},
    ]
  },
//自身綁定事件
  {
   elem:xxx,
   handlers:[
      {type: "click", origType: "click", data: undefined, handler: ?, guid: 3},
      {type: "click", origType: "click", data: undefined, handler: ?, guid: 4},
    ]
  },
]

(5)回過頭再往下看dispatch 源碼,是兩個while循環,舉個例子來說明下:

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

那么會
先循環并執行委托事件,
handler=function (event) {console.log(event,"點擊了B,即B委托A的click事件被點擊了")}
再循環并執行目標元素自身綁定事件,
handler=function (event) {console.log(event,"A被點擊了")}
前提是冒泡不被阻止

最后,執行click事件的事件處理程序的關鍵代碼如下:

handleObj.handler.apply( matched.elem, args )

(完)

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104663.html

相關文章

  • jQuery源碼解析你并不真的懂事件委托及target和currenttarget的區別

    摘要:源碼源碼行被點擊了點擊了,即委托的事件被點擊了優先添加委托,再添加其他即委托在上的事件數量在下標為的位置插入委托事件解析可以看到,是優先添加委托事件,再添加自身事件,觸發事件的時候也是按這個順序。 showImg(https://segmentfault.com/img/remote/1460000019419722); 前言:請先回顧下我之前寫的一篇文章:JavaScript之事件委...

    khs1994 評論0 收藏0
  • jQuery事件綁定到觸發全過程及知識點補充

    摘要:十的觸發機制被點擊了元素本身綁定了一個事件,但是是原生事件,它是靠綁定來觸發事件的。 showImg(https://segmentfault.com/img/remote/1460000019505402); 前言:最重要的還是最后的流程圖,可以試著根據流程圖手寫實現$().on(),下篇文章會放出模擬實現的代碼。 一、舉例 這是A 這是C ...

    Jioby 評論0 收藏0
  • jQuery 源碼系列(十三)事件處理源碼

    摘要:專門為事件建立一個有問題,直接退出如果是一個事件處理對象,且有屬性。參考源碼分析事件體系結構解密事件核心綁定設計一解密事件核心委托設計二本文在上的源碼地址,歡迎來。 歡迎來我的專欄查看系列文章。 通過前面一章對于 addEvent 庫的介紹,它的兼容性超級棒,據說對于 IE4、5 都有很好的兼容性,這和 jQuery 的原理是一致的,而在 jQuery 中,有一個對象與其相對應,那就是...

    劉厚水 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<