When I am using on() to listen to event, I find the event handler is called more than once. Code as below:
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');
});
- Then the 'validate' handler is called twice.
- When I dig into JQuery source code, I find that JQuery will find the parent node of event target and check the seletor matched or not.
- If matched the selector, the handler queue will be pushed one more the handleobj. In the example, between event target and listener element div#contianer, there are two hierarchical divs.
- In result, the handler queue has two event handler which are the same event handler function instance.
My question is: How to use selector correctly to prevent event handler be called more than once? Thanks.
I think to answer this question, we should carefully read the related source code in 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 });
}
}
}
}