谁能解释一下JavaScript中的事件委托,它是如何有用的?


当前回答

委托的概念

如果在一个父元素中有许多元素,并且您希望处理其中的事件—不要将处理程序绑定到每个元素。 相反,将单个处理程序绑定到它们的父处理程序,并从event.target获取子处理程序。 这个站点提供了关于如何实现事件委托的有用信息。 http://javascript.info/tutorial/event-delegation

其他回答

委托是一种技术,在这种技术中,一个对象向外部表达某种行为,但实际上将实现该行为的责任委托给一个关联对象。乍听起来,这与代理模式非常相似,但其目的却大不相同。委托是一种集中对象(方法)行为的抽象机制。

一般来说:使用委托来替代继承。继承是一个很好的策略,当父对象和子对象之间存在密切的关系时,但是,继承会非常紧密地结合对象。通常,委托是表达类之间关系的更灵活的方式。

这种模式也称为“代理链”。其他一些设计模式使用委托——状态模式、策略模式和访问者模式都依赖于它。

Dom事件委托与计算机科学的定义有所不同。

它指的是处理来自许多元素(如表单元格)、来自父对象(如表)的冒泡事件。它可以使代码更简单,特别是在添加或删除元素时,并节省一些内存。

事件委托利用了JavaScript事件中两个经常被忽视的特性:事件冒泡和目标元素。当一个事件在一个元素上被触发时,例如鼠标点击一个按钮,同样的事件也会在该元素的所有祖先上被触发。这个过程被称为事件冒泡;事件从初始元素冒泡到DOM树的顶部。

Imagine an HTML table with 10 columns and 100 rows in which you want something to happen when the user clicks on a table cell. For example, I once had to make each cell of a table of that size editable when clicked. Adding event handlers to each of the 1000 cells would be a major performance problem and, potentially, a source of browser-crashing memory leaks. Instead, using event delegation, you would add only one event handler to the table element, intercept the click event and determine which cell was clicked.

这基本上就是如何关联元素。.click应用于当前DOM,而.on(使用委托)将继续对事件关联后添加到DOM的新元素有效。

哪一种更好,要看具体情况而定。

例子:

<ul id="todo">
   <li>Do 1</li>
   <li>Do 2</li>
   <li>Do 3</li>
   <li>Do 4</li>
</ul>

.Click事件:

$("li").click(function () {
   $(this).remove ();
});

事件内:

$("#todo").on("click", "li", function () {
   $(this).remove();
});

注意,我在.on中分离了选择器。我会解释为什么。

让我们假设,在这种联系之后,让我们做以下的事情:

$("#todo").append("<li>Do 5</li>");

这就是你会注意到区别的地方。

如果事件是通过.click关联的,任务5将不服从click事件,因此它将不会被删除。

如果它是通过.on关联的,选择器是分开的,它将服从。

事件委托允许您避免向特定节点添加事件侦听器;相反,事件侦听器被添加到一个父级。该事件侦听器分析冒泡事件以在子元素上找到匹配。

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>

Let's also say that something needs to happen when each child element is clicked. You could add a separate event listener to each individual LI element, but what if LI elements are frequently added and removed from the list? Adding and removing event listeners would be a nightmare, especially if addition and removal code is in different places within your app. The better solution is to add an event listener to the parent UL element. But if you add the event listener to the parent, how will you know which element was clicked?

简单:当事件弹出到UL元素时,检查事件对象的target属性以获得对实际单击的节点的引用。下面是一个非常基本的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!");
    }
});

Start by adding a click event listener to the parent element. When the event listener is triggered, check the event element to ensure it's the type of element to react to. If it is an LI element, boom: we have what we need! If it's not an element that we want, the event can be ignored. This example is pretty simple -- UL and LI is a straight-forward comparison. Let's try something more difficult. Let's have a parent DIV with many children but all we care about is an A tag with the classA CSS class:

// 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....
                }
            }
        }
    }
});

http://davidwalsh.name/event-delegate