TL;TiM:活动委派*更好.
Event target
vs currentTarget
Event.target might not be your btn
Button.
Say the click casually landed on an icon inside of your button <button type="button">Contact <i class="icon-envelope"></i></button>
, the Event.target would be — your icon!
To get your button Element (on which the handler is attached) use Event.currentTarget.
拇指法则非常简单:
- Always use Event.currentTarget(即使建议不同,除非你真的、真的知道自己在做什么)
- 在需要的时候使用Event.target,比如:从点击的地方获得最近的祖先(或self).一、 e:
if (!evt.target.closest("#popup")) // Click landed outside of #popup. Close the popup
-或使用活动委派时(稍后将详细介绍).
变量与参数性能
There's not much difference in performance in using a variable holding a single Element vs. the Event argument, other than perhaps memory and engine implementation.
If btn
is a single Element stored in a variable, it already is the currentTarget: btn === e.currentTarget // always true
therefore it's eventually up to your use case, and that's if you need to reuse the btn
variable in other parts of the app, which would reduce queries to the DOM.
If instead btns
is a huge NodeList, such as the one given back by const btns = ancestorElement.querySelectorAll("selector")
, memory could be a factor.
on*
event handlers are arguably bad
onmouseleave
和其他on*
处理程序应该是not be used-除非您正在从内存中创建(在一个非常小且可读的脚本中)全新的元素,或者您有意要覆盖之前分配的相同eventName的on*
处理程序侦听器.
Use 100 instead和第三个参数选项{once: true}
(如果只需要一次事件处理程序).
第三,改进版本:
const addActive = (evt) => {
const elBtn = evt.currentTarget;
elBtn.classList.add("active");
elBtn.addEventListener("pointerleave", () => {
console.log("leave");
}, {once: true});
};
// Since you're using classes instead of ID,
// make sure to refer to All of your elements by class,
// and assign an event listener to all of them:
const elsBtns = document.querySelectorAll('.example');
elsBtns.forEach((elBtn) => {
elBtn.addEventListener("click", addActive);
});
或者如果需要"mouseleave"或"pointerleave"always:
const handleClick = (evt) => {
const elBtn = evt.currentTarget;
elBtn.classList.add("active");
};
const handleLeave = () => {
console.log("leave");
};
const elsBtns = document.querySelectorAll('.example');
elsBtns.forEach((elBtn) => {
elBtn.addEventListener("click", handleClick);
elBtn.addEventListener("mouseleave", handleLeave);
});
活动委派
Say you have thousands of buttons. Storing them all in a variable might consume loads of memory (unless till the value is garbage collected). What better solution do we have?
Instead of a NodeList collection of N elements hanging in memory, and assigning to every single one a function handler for a specific Event: target a single common, static parent or ancestor:
document.querySelector("#commonParent").addEventListener("click", (evt) => {
const elBtn = evt.target.closest(".example");
if (elBtn) {
// a .example ButtonElement was clicked.
// Do something:
elBtn.classList.add("active");
}
});
事件委派不仅很好,因为它是memory friendly,它还适用于添加到DOM中的当前或future 元素.
另外,这也是使用特定事件时最常用的另一种情况.目标-但正如您所看到的,它再次与Element.closest()方法相结合.