JavaScript事件委托

先讲讲DOM事件流:DOM2级事件 规定的事件流包括三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段;在DOM事件流中,实际的目标在捕获阶段不会收到事件,紧接着是目标阶段事件发生,并在事件处理中被看成冒泡阶段的一部分,最后冒泡阶段发生,事件又传播回文档;

事件阶段:

  当一个DOM事件被触发的时候,他并不是只在它的起源对象上触发一次,而是会经历三个不同的阶段。简而言之:事件一开始从文档的根节点流向目标对象(捕获阶段),然后在目标对向上被触发(目标阶段),之后再回溯到文档的根节点(冒泡阶段)如图所示

事件委托(event delegation)

对“事件处理程序过多”问题的解决方案是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

避免对特定的每个节点添加事件监听,相反,事件监听器是被添加到他们的父元素上,事件监听器会分析从子元素冒泡上来的事件,找到是哪个字元素的事件。

如下例子,每个单独的<li>元素被点击时有各自不同的事件发生,如果给它们分别单独绑定事件,但这些<li>元素有可能会被删除也有可能会新增系元素,那么监听将会变得很棘手;

例子:

<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的事件冒泡到父元素《ul》时可以检查到对象的target属性,捕获真正被点击的节点元素的引用:

// 找到父元素,添加监听器
document.getElementById("parent-list").addEventListener("click",function(e) {
    // e.target是被点击的元素!
    // 如果被点击的是li元素
    if(e.target && e.target.nodeName == "li") {
        // 找到目标,输出ID!
        console.log("List item "+e.target.id.replace("post-")+" was clicked!");
    }
});

我们先给父元素添加事件监听器,当有事件触发监听器时检查事件的来源,如果是一个li元素则找到了目标,如果不是则忽略该事件。

// 获得父元素DIV, 添加监听器...
document.getElementById("myDiv").addEventListener("click",function(e) {
    // e.target是被点击的元素
    if(e.target && e.target.nodeName == "A") {
        // 获得CSS类名
        var classes = e.target.className.split(" ");
        // 搜索匹配!
        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....

                }
            }
        }

    }
});

JavaScript事件代理和委托以及事件的三个阶段详细可以查看:https://segmentfault.com/a/1190000002613617

posted @ 2016-03-14 13:30  Decmber  阅读(176)  评论(0编辑  收藏  举报