在 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();
}
当现有或动态元素(将来添加到 DOM 中)收到事件时需要执行某个函数时使用 事件委托
该策略是将事件监听器分配给已知的 静态父级 并遵循以下 规则 :
evt.currentTarget
获取 #staticParent
父 委托人
evt.target
获取 exact clicked Element (警告!这也可能是后代元素,不一定是那个 .dynamic
)
片段示例:
document.querySelector("#staticParent").addEventListener("click", (evt) => {
const elChild = evt.target.closest(".dynamic");
if ( !elChild ) return; // do nothing.
console.log("Do something with elChild Element here");
});
具有动态元素的完整示例:
// DOM utility functions:
const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Delegated events
el("#staticParent").addEventListener("click", (evt) => {
const elDelegator = evt.currentTarget;
const elChild = evt.target.closest(".dynamicChild");
const elTarget = evt.target;
console.clear();
console.log(`Clicked:
currentTarget: ${elDelegator.tagName}
target.closest: ${elChild?.tagName}
target: ${elTarget.tagName}`)
if (!elChild) return; // Do nothing.
// Else, .dynamicChild is clicked! Do something:
console.log("Yey! .dynamicChild is clicked!")
});
// Insert child element dynamically
setTimeout(() => {
el("#staticParent").append(elNew("article", {
className: "dynamicChild",
innerHTML: `Click here!!! I'm added dynamically! <span>Some child icon</span>`
}))
}, 1500);
#staticParent {
border: 1px solid #aaa;
padding: 1rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dynamicChild {
background: #eee;
padding: 1rem;
}
.dynamicChild span {
background: gold;
padding: 0.5rem;
}
<section id="staticParent">Click here or...</section>
或者,你可以在创建时直接在子项上附加一个点击处理程序:
// DOM utility functions:
const el = (sel, par) => (par || document).querySelector(sel);
const elNew = (tag, prop) => Object.assign(document.createElement(tag), prop);
// Create new comment with Direct events:
const newComment = (text) => elNew("article", {
className: "dynamicChild",
title: "Click me!",
textContent: text,
onclick() {
console.log(`Clicked: ${this.textContent}`);
},
});
//
el("#add").addEventListener("click", () => {
el("#staticParent").append(newComment(Date.now()))
});
#staticParent {
border: 1px solid #aaa;
padding: 1rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.dynamicChild {
background: #eee;
padding: 0.5rem;
}
<section id="staticParent"></section>
<button type="button" id="add">Add new</button>
资源: