jquery event delegate Detailed jQuery-1.9.1 source code analysis series (X) event system - Event commissioned

jQuery event delegate process flow


  The last chapter analyzes jQuery.event.add time has analyzed the event binding, then the binding part of the source code to extract

IF (! (EventHandle = elemData.handle)) {
         EventHandle = elemData.handle = function (E) { 
            // When an event is called after the page has been uninstalled, then give up jQuery.event.trigger () of the second event, 
            ! return typeof jQuery == core_strundefined && (E || jQuery.event.triggered == e.type!!)? 
            jQuery.event.dispatch.apply (eventHandle.elem, arguments the): 
            undefined; 
        }; 
        // as the elem a function to prevent the handle feature ie non-local memory leak event caused 
        eventHandle.elem = elem; 
    } 
...
// non-custom event, if the special event handler returns false, then only use the addEventListener / the attachEvent IF (special! || special.setup.call .setUp (elem, the Data, Namespaces, EventHandle) === false) { // bind to the global event element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } }

  Bound to the event on the elem process is eventHandle, when the final execution eventHandle the actual execution of the event is scheduled jQuery.event.dispatch. Event scheduling process is actually handling the entrusted flow of events, because the response processing of this node will eventually be attached to the delegate process behind the list.

  Event schedule for the process

  1. event construct a writable jQuery.Event object from a local event object. And replace the local mass participation in the event object with the object

// write from a local event object constructor jQuery.Event 
Event = jQuery.event.fix (Event); 
...
// use correction nice jQuery.Event instead (read-only) local event
args [0] Event =;
event.delegateTarget = the this;

  Structure of local events event are as follows

  

  Use local event construct a new event object jQuery.Event structure is as follows

  

  OriginalEvent where the value of the property is a local event object. The structure of the event object has many attributes are extracted directly from the local to the event object.

 

  2. 获取当前节点缓存中对应事件类型的事件处理列表

        handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],

  事件处理列表的的顺序是委托事件处理在前面,最后才是直接绑定到当前节点的事件处理。

 

  3. 用当前节点替换jQuery.event.handlers的调用者并执行之,获取到符合要求的委托处理函数队列(这个队列最后会加上绑定到节点本身的处理事件)

//获取指定的事件处理队列,主要使用event.target事件源节点不断循环往上查找父节点,
//看些节点和是否在handlers中的选择器对应的节点中
handlerQueue = jQuery.event.handlers.call( this, event, handlers );

  详细分析一下jQuery.event.handlers中获取符合要求的委托处理函数队列。

  jQuery.event.handlers先将委托事件处理取出来放在处理队列handlerQueue中。

  查找的过程是:先取出事件源cur = event.target;然后在确定有委托处理的情况下从事件源开始往他的祖先节点查询,直到this节点以下,遍历事件源到this节点(不包含this节点)的每个节点,在遍历中二次遍历委托事件列表中的每一个委托事件处理所指定的响应节点(委托事件处理对象的selector所指定)是否包含当前遍历节点(事件源到this节点中的当前节点)【handleObj.needsContext ?jQuery( sel, this ).index( cur ) >= 0 :jQuery.find( sel, this, null, [ cur ] ).length】,如果包含则往事件处理队列handlerQueue中压入该委托处理。源码如下

if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
  //冒泡父节点,找到匹配的委托事件存入handlerQueue队列
  for ( ; cur != this; cur = cur.parentNode || this ) {
    if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
      matches = [];
      for ( i = 0; i < delegateCount; i++ ) {
        // 避免和Object.prototype属性冲突(#13203)
        sel = handleObj.selector + " ";
        if ( matches[ sel ] === undefined ) {
          matches[ sel ] = handleObj.needsContext ?
          jQuery( sel, this ).index( cur ) >= 0 :
          jQuery.find( sel, this, null, [ cur ] ).length;
        }
          
        if ( matches[ sel ] ) {
          matches.push( handleObj );
        }
      }
      //添加委托处理到队列中
      if ( matches.length ) {
        handlerQueue.push({ elem: cur, handlers: matches });
      }
    }
  }
}

  最后将直接绑定到当前节点的处理也压入执行

//添加直接绑定的事件到handlerQueue队列中
if ( delegateCount < handlers.length ) {
  handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
}

  

  4. 执行事件处理队列handlerQueue中的处理函数

//先运行代理,他们可能是阻止冒泡的,我们可以利用这一点
i = 0;
while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
        event.currentTarget = matched.elem;

        j = 0;
        while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {

            //触发事件的条件:1)没有命名空间,或
            // 2)有命名空间的子集或等于那些边界事件(他们两者都可以没有命名空间)
            if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {

                event.handleObj = handleObj;
                event.data = handleObj.data;
                //执行
                ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
                .apply( matched.elem, args );

                if ( ret !== undefined ) {
                    if ( (event.result = ret) === false ) {
                        event.preventDefault();
                        event.stopPropagation();
                    }
                }
            }
        }
    }

  此篇文章是帮助理解jQuery.event.handlers中获取符合要求的委托处理函数队列的,自己看源码一直不太明白,看@chua1989大佬的jQuery-1.9.1源码分析系列(十) 事件系统——事件委托关于这一段也没讲太清,自己通过各种调试一步一步总算理解了,借大佬的文章再梳理一遍,防止日后忘记特此记录,致敬chua1989大佬

Guess you like

Origin www.cnblogs.com/changzz/p/12015768.html
Recommended