【发布时间】:2013-07-06 08:01:53
【问题描述】:
当我使用 on() 监听事件时,我发现事件处理程序被多次调用。代码如下:
html:
<div id="container">
<div>
<div><input type="text"/></div>
</div>
</div>
JS:
var $div = $('#container'), $input = $('input');
$div.on('validate', 'div', function() {
console.log('div');
});
$input.blur(function() {
$(this).trigger('validate');
});
- 然后“验证”处理程序被调用两次。
- 当我深入研究 JQuery 源码,我发现JQuery会找到事件的父节点 目标并检查选择器是否匹配。
- 如果匹配选择器, 处理程序队列将再推一个handleobj。在里面 例如,在事件目标和侦听器元素 div#contianer 之间, 有两个分层 div。
- 结果,处理程序队列有两个 事件处理器是同一个事件处理器函数实例。
我的问题是:如何正确使用选择器来防止事件处理程序被多次调用?谢谢。
我认为要回答这个问题,我们应该仔细阅读JQuery中的相关源码:
// Determine handlers that should run if there are delegated events
// Avoid non-left-click bubbling in Firefox (#3861)
if ( delegateCount && !(event.button && event.type === "click") ) {
// Pregenerate a single jQuery object for reuse with .is()
jqcur = jQuery(this);
jqcur.context = this.ownerDocument || this;
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
// Don't process events on disabled elements (#6911, #8165)
if ( cur.disabled !== true ) {
selMatch = {};
matches = [];
jqcur[0] = cur;
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
sel = handleObj.selector;
if ( selMatch[ sel ] === undefined ) {
selMatch[ sel ] = (
handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
);
}
if ( selMatch[ sel ] ) {
matches.push( handleObj );
}
}
if ( matches.length ) {
handlerQueue.push({ elem: cur, matches: matches });
}
}
}
}
【问题讨论】:
-
添加代码示例链接:jsfiddle.net/ianjiang/egcVb
-
我想你看到的是事件委托/传播。一些事件将 DOM 层次结构向上传播到父级。您可以使用
event.stopPropagation()停止传播。 -
我不知道为什么,但如果你在
console.log语句之后执行return false;,它只会记录一次。 -
是的,我意识到 JQuery 自定义事件通过触发器可以冒泡。但这是设计使然吗?一旦选择器匹配,处理程序队列将再添加一个相同的处理程序。