1

当我使用 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');
});

这是更新的DEMO

  • 然后“验证”处理程序被调用两次。
  • 当我深入研究 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 });
                    }
                }
            }
        }
4

3 回答 3

0

如果您有充分的理由将事件处理程序绑定到div而不是input,则可以将事件处理程序更改为如下所示:

$div.on('validate', '*', function(event) {
    var isRelevant = false;
    $(this).children().each(function(){
        if (this === event.target){
            isRelevant = true;
        }
    });

    if (isRelevant){
        console.log('div');
    }
});

此代码段检查事件发出的event.target ( doc ) 是否是事件传播到的元素的直接子元素之一。 isRelevant适用于内部 div。

您也可以在我从您的示例中提取的叉子中查看它:http: //jsfiddle.net/BwseN/

于 2013-07-06T08:41:43.373 回答
0

$input.blur(function() {$(this).trigger('validate');});' 只有输入触发器验证事件。所以我不认为意味着“为 DOM 上的每个元素工作 onblur

这是错误的,因为触发器会在 DOM 树上冒泡,并为父元素触发相同的事件。

来自文档

从 jQuery 1.3 开始,.trigger()ed 事件在 DOM 树中冒泡;事件处理程序可以通过从处理程序返回 false 或在传递给事件的事件对象上调用 .stopPropagation() 方法来停止冒泡

所以里面有两个div div#container

$input.blur(function() {$(this).trigger('validate');});

也触发了这两个 div。

这是一个示例,您可以看到哪个元素是currentTarget

http://jsfiddle.net/egcVb/4/

$div.on('validate', 'div', function(e) {
    console.log(e.currentTarget);
});

如果您想停止冒泡,只需从该事件中返回 false 。

http://jsfiddle.net/egcVb/5/

$div.on('validate', 'div', function(e) {
    console.log(e.currentTarget);
    return false;
});
于 2013-07-06T08:09:55.077 回答
0

这意味着:在 $div 上绑定“验证”事件,但也为每个 div 后代包含它。

$div.on('validate', 'div', function() {
    console.log('div');
});

jQueryon,参数selector

一个选择器字符串,用于过滤触发事件的选定元素的后代。如果选择器为 null 或省略,则始终在到达所选元素时触发事件。

用这个:

$div.on('validate', function() {
    console.log('div');
});

...您将只处理一个事件。

于 2013-07-06T08:23:35.510 回答