在 vanilla js 中进行事件委托的最佳方式(最快/正确)是什么?例如,如果我在 jQuery 中有这个:$('#main').on('click', '.focused', function(){ settingsPanel();})...
在 vanilla js 中进行事件委托的最佳方式(最快/最合适)是什么?
例如如果我在 jQuery 中有这个:
$('#main').on('click', '.focused', function(){
settingsPanel();
});
我该如何将其转换为原生 js?或许可以用 .addEventListener()
我能想到的方法是:
document.getElementById('main').addEventListener('click', dothis);
function dothis(){
// now in jQuery
$(this).children().each(function(){
if($(this).is('.focused') settingsPanel();
});
}
但这似乎效率低下,特别是在 #main
有很多孩子的情况下。
那么这是正确的做法吗?
document.getElementById('main').addEventListener('click', doThis);
function doThis(event){
if($(event.target).is('.focused') || $(event.target).parents().is('.focused') settingsPanel();
}
我想出了一个简单的解决方案 ,它似乎效果很好(尽管支持旧版 IE)。在这里,我们扩展了 EventTarget
的原型,以提供一种 delegateEventListener
使用以下语法的方法:
EventTarget.delegateEventListener(string event, string toFind, function fn)
我创建了一个相当复杂的 fiddle 来演示它的实际操作,其中我们委托绿色元素的所有事件。停止传播继续起作用,您可以访问应该 event.currentTarget
通过的 this
(与 jQuery 一样)。
以下是完整的解决方案:
(function(document, EventTarget) {
var elementProto = window.Element.prototype,
matchesFn = elementProto.matches;
/* Check various vendor-prefixed versions of Element.matches */
if(!matchesFn) {
['webkit', 'ms', 'moz'].some(function(prefix) {
var prefixedFn = prefix + 'MatchesSelector';
if(elementProto.hasOwnProperty(prefixedFn)) {
matchesFn = elementProto[prefixedFn];
return true;
}
});
}
/* Traverse DOM from event target up to parent, searching for selector */
function passedThrough(event, selector, stopAt) {
var currentNode = event.target;
while(true) {
if(matchesFn.call(currentNode, selector)) {
return currentNode;
}
else if(currentNode != stopAt && currentNode != document.body) {
currentNode = currentNode.parentNode;
}
else {
return false;
}
}
}
/* Extend the EventTarget prototype to add a delegateEventListener() event */
EventTarget.prototype.delegateEventListener = function(eName, toFind, fn) {
this.addEventListener(eName, function(event) {
var found = passedThrough(event, toFind, event.currentTarget);
if(found) {
// Execute the callback with the context set to the found element
// jQuery goes way further, it even has it's own event object
fn.call(found, event);
}
});
};
}(window.document, window.EventTarget || window.Element));