一、起源
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.EventjQuery.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 <use> 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循环,举个例子来说明下:

<div id="A" style="background-color: deeppink">  这是A  <div id="B" style="background-color: bisque">    这是B  </div></div>  $("#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 )

(完)