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

2016-04-18  本文已影响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
这种事件委托的方式减少了事件处理程序,也能降低程序的复杂性和出错概率。

上一篇下一篇

猜你喜欢

热点阅读