相关概念
1. DOM事件流
事件流包括三个阶段:
捕获阶段: 事件从文档的根节点流向目标对象
目标阶段: 在目标对象上被触发
冒泡阶段: 回溯到文档的根节点
2. 事件冒泡
事件从目标元素执行后逐渐向上执行它的祖元素被绑定的事件的现象
3. 事件捕获
事件从最顶级的元素逐渐向下执行它的目标元素被绑定的事件的现象
4. 事件委托原理
把事件监听器设置在其父节点上,然后利用冒泡原理影响每一个子节点
5. 绑定事件addEventListener
语法:addEventListener(type, listener[, useCapture])
添加事件监听
type:表示监听事件类型的字符串。
listener:一个实现了 EventListener 接口的对象,或者是一个函数
useCapture:默认false;true表示在事件捕获阶段调用事件处理程序;false表
在事件冒泡阶段调用事件处理程序。
6. 解除事件removeEventListener解释
语法:removeEventListener(type, listener[, useCapture])
删除事件监听
type:表示监听事件类型的字符串。
listener:一个实现了 EventListener 接口的对象,或者是一个函数
useCapture:默认false;true表示在事件捕获阶段调用事件处理程序;false表
在事件冒泡阶段调用事件处理程序。
二.实例
1. 添加冒泡事件
比如:有三个div,id为two的被id为one的包裹,id为three的被id为two的包裹
<div id="one">one
<div id="two">two
<div id="three">three</div>
</div>
</div>
我们给每一个id添加冒泡点击事件:
<script language="javascript">
var one = document.getElementById('one');
var two = document.getElementById('two');
var three = document.getElementById('three');
one.addEventListener('click', function() {
console.log('one');
}, false);
two.addEventListener('click', function() {
console.log('two');
}, false);
three.addEventListener('click', function() {
console.log('three');
}, false);
</script>
点击three,执行顺序会发生冒泡现象,先触发three,然后是two,最后是one. 即: three <- two <- one
2. 阻止事件冒泡
e.stopPropagation(); 可以阻止事件冒泡,想要从哪个节点开始阻止事件冒泡,就把该语句放到哪个事件处理程序里面
e.stopPropagation();
例如给two的事件回调里添加e.stopPropagation()
one.addEventListener('click', function() {
console.log('one');
}, false);
two.addEventListener('click', function(e) {
console.log('two');
e.stopPropagation()
}, false);
three.addEventListener('click', function() {
console.log('three');
}, false);
点击three,只能依次出现three和two
即:three two
注意e.stopPropagation()有兼容性
if (e && e.stopPropagation()) {
e.stopPropagation() // IE8以下用
} else {
window.event.cancelBubble = true // IE8以上用
}
3. 添加捕获事件
我们给每一个id添加捕获点击事件:
one.addEventListener('click', function() {
console.log('one');
}, true);
two.addEventListener('click', function() {
console.log('two');
}, true);
three.addEventListener('click', function() {
console.log('three');
}, true);
点击three,执行顺序会发生自顶向下的捕获现象,先触发one,然后是two,最后是three
即:one two three
4. 一个DOM元素绑定多个事件时,先执行冒泡还是捕获?
其他元素的捕获事件 -> 本元素事件 -> 其他元素冒泡事件
one.addEventListener('click', function() {
console.log('one');
}, true);
two.addEventListener('click', function() {
console.log('two');
}, false);
three.addEventListener('click', function() {
console.log('three');
}, true);
我们给one和three元素添加捕获,给two添加冒泡,此时点击three元素,
会先执行其他元素的捕获,即one,因为two是冒泡,被省略;
然后是本元素的事件执行,即three;
最后是其他元素的冒泡,从里往外,two是冒泡,one是捕获省略;
即:one three two
5. 委托事件
ul标签里包裹着四个li,如下:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
我们可以通过只操作ul获取每个li的内容
let ul = document.getElementsByTagName('ul')[0];
ul.onclick = function(e) {
if (e.target != ul) {
console.log(e.target.innerText)
}
}
什么是事件委托?
利用冒泡的原理, 把事件加到父级上, 触发执行效果
事件委托的好处?
1.提高性能
2.新添加的元素还会有之前的事件
事件委托处理兼容问题和触发事件
var e = ev || window.event // 处理兼容问题
var target1 = e.target || window.srcElement
三.总结
事件冒泡就好比,你往水中丢一块石头,水波由内而外的散开.事件向上一层层传递.而事件捕获,从上往下一级一级往下找,先找父级在找子级.
事件委托将事件绑定到尽可能层级较高的父元素上,而元素触发事件后会逐级向上冒泡,利用事件对象event来判断事件冒泡是否传播到我们需要绑定事件的元素上