什么是 DOM 事件委派?
任何人都可以解释一下JavaScript中的事件委托,以及它有什么用处吗?
任何人都可以解释一下JavaScript中的事件委托,以及它有什么用处吗?
DOM 事件委派是一种通过单个公共父级而不是每个子级响应 ui 事件的机制,通过事件“冒泡”(也称为事件传播)的魔力。
在元素上触发事件时,将发生以下情况:
将事件调度到其目标,并触发在那里找到的任何事件侦听器。然后,冒泡事件将触发通过向上跟踪的父链找到的任何其他事件侦听器,检查在每个连续的事件目标上注册的任何事件侦听器。这种向上传播将一直持续到 .
EventTarget
EventTarget
Document
事件冒泡为浏览器中的事件委派提供了基础。现在,您可以将事件处理程序绑定到单个父元素,并且只要事件在其任何子节点(以及它们的任何子节点)上发生,该处理程序就会被执行。这是事件委派。下面是实践中的一个示例:
<ul onclick="alert(event.type + '!')">
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
使用该示例,如果要单击任何子节点,您将看到 警报 ,即使没有将单击处理程序绑定到您单击的 节点也是如此。如果我们绑定到每个,你会得到相同的效果。<li>
"click!"
<li>
onclick="..."
<li>
那么有什么好处呢?
想象一下,您现在需要通过 DOM 操作将新项动态添加到上面的列表中:<li>
var newLi = document.createElement('li');
newLi.innerHTML = 'Four';
myUL.appendChild(newLi);
如果不使用事件委派,则必须将事件处理程序“重新绑定”到新元素,以便它的行为方式与其同级元素相同。使用事件委派,您无需执行任何操作。只需将新内容添加到列表中即可完成。"onclick"
<li>
<li>
对于将事件处理程序绑定到许多元素的Web应用程序来说,这绝对是非常棒的,其中新元素是在DOM中动态创建和/或删除的。使用事件委派,通过将事件绑定移动到公共父元素,可以大大减少事件绑定的数量,并且可以动态创建新元素的代码与绑定其事件处理程序的逻辑分离。
事件委派的另一个好处是事件侦听器使用的总内存占用量会减少(因为事件绑定的数量会减少)。对于经常卸载的小页面(即用户经常导航到不同的页面),它可能没有太大区别。但对于长期应用来说,它可能很重要。当从 DOM 中删除的元素仍然声明内存(即它们泄漏)时,存在一些非常难以跟踪的情况,并且通常此泄漏的内存与事件绑定相关联。通过事件委派,您可以自由销毁子元素,而不会忘记“解除绑定”其事件侦听器(因为侦听器位于祖先上)。然后可以遏制这些类型的内存泄漏(如果不消除,有时很难做到。IE我在看着你)。
以下是事件委派的一些更好的具体代码示例:
焦点
和模糊
事件(不会冒泡)的有趣方法事件委派允许您避免将事件侦听器添加到特定节点;而是将事件侦听器添加到一个父级。该事件侦听器分析气泡事件以查找子元素上的匹配项。
JavaScript 示例 :
假设我们有一个包含多个子元素的父 UL 元素:
<ul id="parent-list">
<li id="post-1">Item 1</li>
<li id="post-2">Item 2</li>
<li id="post-3">Item 3</li>
<li id="post-4">Item 4</li>
<li id="post-5">Item 5</li>
<li id="post-6">Item 6</li>
</ul>
我们还假设在单击每个子元素时需要发生某些事情。您可以为每个单独的 LI 元素添加一个单独的事件侦听器,但是如果 LI 元素经常在列表中添加和删除,该怎么办?添加和删除事件侦听器将是一场噩梦,尤其是当添加和删除代码位于应用内的不同位置时。更好的解决方案是将事件侦听器添加到父 UL 元素。但是,如果将事件侦听器添加到父级,您将如何知道单击了哪个元素?
简单:当事件冒泡到 UL 元素时,检查事件对象的目标属性以获取对实际单击的节点的引用。下面是一个非常基本的 JavaScript 代码段,它说明了事件委派:
// Get the element, add a click listener...
document.getElementById("parent-list").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
if(e.target && e.target.nodeName == "LI") {
// List item found! Output the ID!
console.log("List item ", e.target.id.replace("post-"), " was clicked!");
}
});
首先向父元素添加单击事件侦听器。触发事件侦听器时,检查事件元素以确保它是要响应的元素类型。如果是LI元件,轰:我们有我们需要的东西!如果它不是我们想要的元素,则可以忽略该事件。这个例子非常简单 - UL和LI是一个直接的比较。让我们尝试一些更困难的事情。让我们有一个包含许多子类的父 DIV,但我们所关心的只是一个带有 classA CSS 类的 A 标记:
// Get the parent DIV, add click listener...
document.getElementById("myDiv").addEventListener("click",function(e) {
// e.target was the clicked element
if(e.target && e.target.nodeName == "A") {
// Get the CSS classes
var classes = e.target.className.split(" ");
// Search for the CSS class!
if(classes) {
// For every CSS class the element has...
for(var x = 0; x < classes.length; x++) {
// If it has the CSS class we want...
if(classes[x] == "classA") {
// Bingo!
console.log("Anchor element clicked!");
// Now do something here....
}
}
}
}
});