事件流:简单来说就是事件执行顺序;事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即DOM事件流
两种事件模型
捕获型事件流 和 冒泡型事件流
DOM2级事件流的三个阶段
- 事件捕获阶段:从外到内传播即从根节点向最内侧节点传播
- 处于目标阶段:事件到达具体点击的那个元素时
- 事件冒泡阶段:从内向外传播直到根节点结束
DOM事件捕获的具体流程
事件捕获:window ——> document ——> html ——> body ——> 目标元素
事件冒泡:上面的顺序反过来
事件执行次数
触发一个事件后对应的代码只会执行一次,这是因为默认情况下只会经过事件冒泡流传播,而不会触发捕获流,所以在触发事件后对应的代码只会执行一次,然后依次向上冒泡。
阻止冒泡
无论事件是以冒泡模式传播还是以捕获模式传播,都会有一个问题,有时候不想让事件向上或向下传播,即触发哪个元素的事件,事件就停留在哪个元素而不进行传播。
阻止冒泡的方法就是 stopPropagation()
<div id="clickMe">ClickMe</div>
<script>
var div = document.querySelector('#clickMe');
div.addEventListener('click', function(event){
console.log('事件冒泡被阻止了');
event.stopPropagation();
});
</script>
运用实例
事件委托
实现原理:利用事件冒泡流
事件委托:当一组元素要添加相同的事件时,可以在父元素上绑定一个事件,利用事件冒泡原理,达到父元素代理子元素事件,点击子元素,通过 e.target || e.srcElement 可以获取点击的具体子元素
事件委托的优点
可以减少事件的注册,节省内存,也可以实现当新增对象时无需再次对其绑定事件(动态绑定)
addEventListener的第三个参数
第三个参数默认是 false,表示在事件冒泡阶段调用;当该值为 true 表示在事件捕获阶段调用
验证整个事件流执行顺序(先捕获再冒泡)
// 鼠标点击子元素后,打印顺序为
// 父捕获
// 子捕获
// 子冒泡
// 父冒泡
<html>
<div class="parent">
<div class="child">子元素</div>
</div>
<script>
let parentDom = document.querySelector('.parent');
parentDom.addEventListener('click', function () {console.log('父捕获'); }, true)
parentDom.addEventListener('click', function () {console.log('父冒泡');}, false)
let childDom = document.querySelector('.child')
childDom.addEventListener('click', function () {console.log('子捕获');}, true)
childDom.addEventListener('click', function () {console.log('子冒泡');}, false)
</script>
</html>