香草JavaScript事件代表团 [英] Vanilla JavaScript Event Delegation
问题描述
在vanilla js中进行事件委托的最佳方式(最快/正确)是什么?
What is the best way ( fastest / proper ) fashion to do event delegation in vanilla js?
例如,如果我在jQuery中有这个:
For example if I had this in jQuery:
$('#main').on('click', '.focused', function(){
settingsPanel();
});
如何将其翻译为vanilla js?也许用 .addEventListener()
How can I translate that to vanilla js? Perhaps with .addEventListener()
我能想到这样做的方式是:
The way I can think of doing this is:
document.getElementById('main').addEventListener('click', dothis);
function dothis(){
// now in jQuery
$(this).children().each(function(){
if($(this).is('.focused') settingsPanel();
});
}
但这似乎效率低下,特别是如果 #main
有很多孩子。
But that seems inefficient especially if #main
has many children.
这是正确的方法吗?
document.getElementById('main').addEventListener('click', doThis);
function doThis(event){
if($(event.target).is('.focused') || $(event.target).parents().is('.focused') settingsPanel();
}
推荐答案
我想出了一个简单的解决方案 ,这似乎工作得很好(尽管有传统的IE支持)。我们扩展 EventTarget
的原型,以提供 delegateEventListener
方法d使用以下语法:
I've come up with a simple solution which seems to work rather well (legacy IE support notwithstanding). Here we extend the EventTarget
's prototype to provide a delegateEventListener
method which works using the following syntax:
EventTarget.delegateEventListener(string event, string toFind, function fn)
我创建了一个相当复杂的 小提琴 来演示它在行动中,我们委托绿色元素的所有事件。停止传播继续工作,您可以访问 event.currentTarget
到这个
(与jQuery一样)。
I've created a fairly complex fiddle to demonstrate it in action, where we delegate all events for the green elements. Stopping propagation continues to work and you can access what should be the event.currentTarget
through this
(as with 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));
这篇关于香草JavaScript事件代表团的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!