[英]Is using a variable in an onclick worse than using e.target?
Wondering if there is a performance/memory area I could improve when setting onclick
listeners to elements.想知道在将onclick
侦听器设置为元素时是否有可以改进的性能/内存区域。
Example:例子:
let btn = document.querySelector('.example')
btn.addEventListener('click', (e) => {
btn.classList.add('active');
btn.onmouseleave = () => {
console.warn('leave')
}
})
compared to:相比:
let btn = document.querySelector('.example')
btn.addEventListener('click', (e) => {
e.target.classList.add('active');
e.target.onmouseleave = () => {
console.warn('leave')
}
})
I would think that using btn
would take a lot more work as the computer has to save the variable and remember it, whereas e.target uses the event temporarily.我认为使用btn
需要做更多的工作,因为计算机必须保存变量并记住它,而 e.target 暂时使用该事件。 Which one is best for the least amount of memory consumption?哪一个最适合最少的内存消耗?
TL;TiM : Event delegation* is better. TL;TiM :事件委托*更好。
target
vs currentTarget
事件target
与currentTarget
Event.target might not be your btn
Button. Event.target可能不是您的btn
按钮。
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!假设点击随意落在按钮<button type="button">Contact <i class="icon-envelope"></i></button>
内的图标上,Event.target 将是 - 您的图标!
To get your button Element (on which the handler is attached ) use Event.currentTarget .要获取您的按钮元素(处理程序附加在其上),请使用Event.currentTarget 。
The rule of thumbs is really simple:经验法则非常简单:
if (!evt.target.closest("#popup")) // Click landed outside of #popup. Close the popup
即: if (!evt.target.closest("#popup")) // Click landed outside of #popup. Close the popup
if (!evt.target.closest("#popup")) // Click landed outside of #popup. Close the popup
- or when using Event delegation (more on that later). 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.除了内存和引擎实现之外,使用包含单个 Element的变量与Event 参数在性能上没有太大差异。
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.如果btn
是存储在变量中的单个元素,则它已经是currentTarget: btn === e.currentTarget // always true
,因此最终取决于您的用例,如果您需要在其他部分重用btn
变量应用程序,这将减少对 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.如果相反btns
是一个巨大的NodeList ,例如由const btns = ancestorElement.querySelectorAll("selector")
返回的那个,那么内存可能是一个因素。
on*
event handlers are arguably bad on*
事件处理程序可以说是不好的onmouseleave
and other on*
handlers should not be used - unless you're creating (in a really small and readable script) brand new Elements from in-memory, or you intentionally want to override a previously assigned on*
handler listener of the same eventName .不应使用onmouseleave
和其他on*
处理程序 - 除非您正在(在一个非常小且可读的脚本中)从内存中创建全新的元素,或者您有意覆盖先前分配的相同eventName的on*
处理程序侦听器.
Use EventTarget.addEventListener() instead with the third argument options {once: true}
(for if an event handler is needed only once).使用EventTarget.addEventListener()代替第三个参数选项{once: true}
(如果事件处理程序只需要一次)。
Third, improved version:三、改进版:
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);
});
or if the "mouseleave" or "pointerleave" is always needed:或者如果总是需要“mouseleave”或“pointerleave”:
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 :而不是挂在内存中的N个元素的 NodeList 集合,并为每个元素分配一个特定事件的函数处理程序:以单个公共、静态父级或祖先为目标:
document.querySelector("#commonParent").addEventListener("click", (evt) => {
const elBtn = evt.target.closest(".example");
if (!elBtn) return; // Do nothing.
// ".example" Element was clicked. Do something:
elBtn.classList.add("active");
});
Event delegation is not only nice because it's memory friendly , it also works for current of future Elements added into the DOM.事件委托不仅很好,因为它对内存友好,它也适用于当前添加到 DOM 中的未来元素。
Also that's the other most used case when using specifically Event.target - but as you can see it's again in combination with the Element.closest() Method.这也是专门使用 Event.target 时最常用的另一种情况 - 但正如您所看到的,它再次与Element.closest()方法结合使用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.