jQueryのイベントデリゲートのプロセスフロー
最後の章では、 jQuery.event.add時間は結合事象抽出するソースコードのその後の結合部分を分析した分析します
elemはプロセス上のイベントにバインドはeventHandle、イベントの実際の実行が予定されているjQuery.event.dispatch eventHandle最終実行です。このノードの応答処理は、最終的にリストの後ろのデリゲートプロセスに添付されますので、イベントスケジューリングプロセスは、実際には、イベントの委託の流れを処理しています。
プロセスのイベントスケジュール
1.イベントは、ローカルイベントオブジェクトから書き込み可能なjQuery.Eventオブジェクトを構築します。そして、オブジェクトとイベントオブジェクト内のローカルマスの参加を置き換えます
ローカルイベントオブジェクトコンストラクタjQuery.Eventから//書き込み イベント= jQuery.event.fix(イベント);
...
//使用補正素敵jQuery.Event代わりに(読み取り専用)ローカルイベント
引数[0]イベント=;
event.delegateTarget =この;
次のように地元のイベントイベントの構造は、
次のように新しいイベントオブジェクトjQuery.Event構造があるローカルイベント構文を使用します
プロパティの値がローカルイベントオブジェクトですOriginalEvent。イベントオブジェクトの構造は、多くの属性は、イベント・オブジェクトへのローカルから直接抽出されています。
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大佬。