在 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();
}
我有一个类似的解决方案来实现事件委托。它利用数组函数 slice
, reverse
, filter
和 forEach
.
slice
将查询中的 NodeList 转换为数组,这必须在允许反转列表之前完成。
reverse
反转数组(使得最终的遍历尽可能接近事件目标。
filter
检查哪些元素包含 event.target
.
forEach
只要处理程序不返回,就会为过滤结果中的每个元素调用提供的处理程序 false
.
函数返回创建的委托函数,这使得稍后可以移除监听器。注意,本机 event.stopPropagation()
不会停止遍历 validElements
,因为冒泡阶段已经遍历到委托元素。
function delegateEventListener(element, eventType, childSelector, handler) {
function delegate(event){
var bubble;
var validElements=[].slice.call(this.querySelectorAll(childSelector)).reverse().filter(function(matchedElement){
return matchedElement.contains(event.target);
});
validElements.forEach(function(validElement){
if(bubble===undefined||bubble!==false)bubble=handler.call(validElement,event);
});
}
element.addEventListener(eventType,delegate);
return delegate;
}
虽然不建议扩展原生原型,但可以将该函数添加到原型中 EventTarget
(或 Node
在 IE 中)。执行此操作时, element
在函数中 this
为 EventTarget.prototype.delegateEventListener = function(eventType, childSelector, handler){...}
)。