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

1.理解事件流

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

JavaScript 事件冒泡、事件捕获和事件委托_第1张图片
event flow

html:

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元素');
    });
}

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

var li = document.getElementsByTagName('li');
for(var i=0; i元素');
    }
});

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

你可能感兴趣的:(JavaScript 事件冒泡、事件捕获和事件委托)