美文网首页
JavaScript 事件冒泡、事件捕获和事件委托

JavaScript 事件冒泡、事件捕获和事件委托

作者: 凌凌西 | 来源:发表于2016-04-18 17:12 被阅读0次

    1.理解事件流

    一言以蔽之,事件捕获是从外层元素到目标元素的过程,事件冒泡是从目标元素到外层元素的过程。如图:

    event flow

    html:

    <div id="wrapper">
        <button id="event">事件处理程序</button>
    </div>
    

    javascript:

    var wrapper = document.getElementById('wrapper');
    var event = document.getElementById('event');
    
    wrapper.addEventListener("click", function(e){
        console.log('捕获阶段执行父元素wrapper的事件处理程序');
    }, true);
    wrapper.addEventListener("click", function(e){
        console.log('冒泡阶段执行父元素wrapper的事件处理程序');
    }, false);
    event.addEventListener("click", function(e){
        console.log('捕获阶段执行子元素event的事件处理程序');
    }, true);
    event.addEventListener("click", function(e){
        console.log('冒泡阶段执行子元素event的事件处理程序');
    }, false);
    

    正如前面所说,这段代码的输出是:

    捕获阶段执行父元素wrapper的事件处理程序
    捕获阶段执行子元素event的事件处理程序
    冒泡阶段执行子元素event的事件处理程序
    冒泡阶段执行父元素wrapper的事件处理程序
    

    Demo

    2.阻止冒泡

    应该在那个阶段执行元素的事件处理程序呢?

    多数情况下,我们希望在触发一个元素的事件处理程序时,不影响它的父元素。比如:点击button,并不希望父元素的click事件处理程序被触发。

    解决方法是:在冒泡阶段执行事件处理程序,然后阻止冒泡。

    wrapper.addEventListener("click", function(e){
        console.log('捕获阶段执行父元素wrapper的事件处理程序');
    }, true); // 默认为false
    wrapper.如何烫染出满意的头发?("click", function(e){
        console.log('冒泡阶段执行父元素wrapper的事件处理程序');
    }, false);
    event.addEventListener("click", function(e){
        console.log('捕获阶段执行子元素event的事件处理程序');
    }, true);
    event.addEventListener("click", function(e){
        var target = e.target;
        e.stopPropagation(); // stop bubbling
        console.log('冒泡阶段执行子元素event的事件处理程序');
    }, false);
    

    输出:

    捕获阶段执行父元素wrapper的事件处理程序
    捕获阶段执行子元素event的事件处理程序
    冒泡阶段执行子元素event的事件处理程序
    

    Demo
    像这样绑定一个事件处理程序就是安全的。

    3.事件委托

    上面的例子是要阻止冒泡,有时候冒泡机制也可以被利用。先看一个问题:

    假设要在页面上放在 10^n(n>=1) 个列表项元素,当我点击某个元素时,需要输出点击的是第几个。

    一般做法是,遍历时给每个元素绑定点击事件:

    var li = document.getElementsByTagName('li');
    for(var i=0; i<li.length; i++){
        li[i].setAttribute('i',i+1);
        li[i].addEventListener('click', function(e){
            var b = this.getAttribute('i');
            console.log('这是第' + b + '个<li>元素');
        });
    }
    

    另一种方法是,可以利用冒泡机制,在父元素只绑定一次点击事件:

    var li = document.getElementsByTagName('li');
    for(var i=0; i<li.length; i++){
        li[i].setAttribute('i',i+1);
    }
    
    var ul = document.getElementById('wrapper');
    ul.addEventListener('click', function(e){
        if(e.target && e.target.nodeName.toUpperCase() === 'LI'){
            var b = e.target.getAttribute('i');
            console.log('这是第' + b + '个<li>元素');
        }
    });
    

    Demo
    这种事件委托的方式减少了事件处理程序,也能降低程序的复杂性和出错概率。

    相关文章

      网友评论

          本文标题:JavaScript 事件冒泡、事件捕获和事件委托

          本文链接:https://www.haomeiwen.com/subject/zudalttx.html