事件流
事件流描述的是从页面中接收事件的顺序。 事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
DOM事件流分为3 个阶段
事件冒泡
IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到DOM最顶层节点的过程。
<div id="first">
<div id="second">
<div id="third"></div>
</div>
</div>
#first {
width: 200px;
height: 200px;
margin: 0 auto;
background: red;
border: 1px solid #ccc;
}
#second {
width: 150px;
height: 150px;
margin: 24px auto;
background: yellow;
border: 1px solid #ccc;
}
#third {
width: 100px;
height: 100px;
margin: 24px auto;
background: blue;
border: 1px solid #ccc;
}
addEventListener 第三个参数是false 那么则处于冒泡阶段,不写则默认为false 。
first.addEventListener('click', function () {
console.log('红色');
});
second.addEventListener('click', function () {
console.log('黄色');
});
third.addEventListener('click', function () {
console.log('蓝色');
});
事件捕获
网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
first.addEventListener('click', function () {
console.log('红色');
},true);
second.addEventListener('click', function () {
console.log('黄色');
},true);
third.addEventListener('click', function () {
console.log('蓝色');
},true);
addEventListener 第三个参数是true 那么则处于捕获阶段。
事件在不同阶段执行
first.addEventListener('click', function () {
console.log('红色');
});
second.addEventListener('click', function () {
console.log('黄色');
},true);
third.addEventListener('click', function () {
console.log('蓝色');
});
JavaScript 代码中只能执行捕获或者冒泡其中的一个阶段,我们可以这么来理解:
- 此处单击蓝色框后,事件捕获阶段
从外向内捕获,到红色时,红色有事件,需在冒泡阶段执行,但此时是捕获阶段,先不执行,接下来是黄色,黄色在捕获阶段执行,所以先执行。 - 到达当前目标阶段
执行目标对象的事件函数,控制台输出蓝色。 - 到达冒泡阶段
由目标向外冒泡,到黄色时,捕获阶段已经执行,最后到达红色,红色在冒泡阶段执行,控制台输出红色。
实际开发中我们很少使用事件捕获,我们更关注事件冒泡。 其中onclick 和attachEvent 只能得到冒泡阶段。 还有些事件是没有冒泡的,比如onblur 、 onfocus 、onmouseenter 、onmouseleave 。
事件委托
假如,当我们需要给ul 中的多个li 添加点击事件时,通常会为每个li 标签加上点击事件,此时看起来每个li 的点击事件触发时调用的都是一个函数,但其实不是这样,每个li 绑定的都是一个全新的函数,只不过样子一模一样,这里我们可以判断一下:
let liList = document.querySelectorAll('li')
for (let i = 0; i < liList.length; i++) {
liList[i].onclick = function () {
console.log(this.innerHTML)
}
}
console.log(liList[0].onclick == liList[1].onclick);
至此,我们可以得到结论,有多少个li ,那么就会有多少个函数被创建在内存中占据空间,这样对内存的开销是巨大的。
前面我们介绍到了事件冒泡的原理,那么我们就可以通过这种机制把事件加在父元素的身上,也就是ul 标签,这样ul 里面的li 做点击事件时,都会冒泡到ul 上,所以都会触发,这就是事件委托,委托它们的父级代为执行事件。
Event对象
- 官方解释:
event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。 - 简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象
event ,它有很多属性和方法。
这个event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去。当我们注册事件时,event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)。
event 对象提供了一个属性叫target ,可以返回事件的目标节点,我们称为事件源,也就是说,target 就可以表示为当前的事件操作的dom ,但不是真正操作dom 。
IE678兼容性解决:e=e||window.event 。 下面我们可以这样改写:
let ul = document.querySelector('ul')
ul.onclick = function (e) {
e = e || window.event
console.log(e.target.innerHTML)
}
这样如果li 数量较多,就可以大大减少dom 操作,优化的性能可想而知。
|