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です

  • 次に、「検証」ハンドラーが 2 回呼び出されます。
  • JQuery ソース コードを掘り下げると、JQuery がイベント ターゲットの親ノードを検出し、セレクターが一致するかどうかを確認することがわかります。
  • セレクターと一致した場合、ハンドラー キューは、handleobj をもう 1 つプッシュされます。この例では、イベント ターゲットとリスナー要素 div#contianer の間に、2 つの階層 div があります。
  • その結果、ハンドラー キューには、同じイベント ハンドラー関数インスタンスである 2 つのイベント ハンドラーがあります。

私の質問は次のとおりです:イベントハンドラーが複数回呼び出されるのを防ぐためにセレクターを正しく使用する方法は? ありがとう。

この質問に答えるには、関連する 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

イベント ハンドラーをinputではなくdivにバインドする正当な理由がある場合は、イベント ハンドラーを次のように変更できます。

$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 ) が、イベントの伝播先の要素の直接の子の 1 つであるかどうかを確認します。 isRelevantは、内側の div に対してのみtrueになります。

あなたの例から作ったフォークでもチェックアウトできます:http://jsfiddle.net/BwseN/

于 2013-07-06T08:41:43.373 に答える