事件冒泡与事件捕获
事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。
如下:假设三层 div 都有事件监听,这时我们点击的小的蓝方框,事件执行的顺序是怎么样的呢
<div id="s1" style="height: 400px;width: 400px;border: 1px solid red"> 红
<div id="s2" style="height: 200px;width: 200px;border: 1px solid yellow">
黄
<div id="s3" style="height: 100px;width: 100px;border: 1px solid blue"> 蓝 </div>
</div>
</div>
事件冒泡
微软提出了名为事件冒泡 (event bubbling) 的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到 document 对象。
因此在事件冒泡的概念下在 div 元素上发生 click 事件的顺序应该是div -> body -> html -> document
事件捕获
网景提出另一种事件流名为事件捕获 (event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。
因此在事件捕获的概念下在 div 元素上发生 click 事件的顺序应该是document -> html -> body -> div -> div
w3c 采用折中的方式,制定了统一的标准——先捕获再冒泡。
addEventListener 第三个参数默认值是 false,表示在事件冒泡阶段调用事件处理函数; 如果参数为 true,则表示在事件捕获阶段调用处理函数。
测试事件冒泡 - 点击蓝色
s1 = document.getElementById('s1')
s2 = document.getElementById('s2')
s3 = document.getElementById('s3')
s1.addEventListener("click",function(e){console.log("红 冒泡事件");// 从底层往上
},false);// 第三个参数默认值是 false,表示在事件冒泡阶段调用事件处理函数; 如果参数为 true,则表示在事件捕获阶段调用处理函数。s2.addEventListener("click",function(e){console.log("黄 冒泡事件");
},false);
s3.addEventListener("click",function(e){console.log("蓝 冒泡事件");
},false);
测试事件捕获 - 点击蓝色
s1.addEventListener("click",function(e){console.log("红 捕获事件");
},true);
s2.addEventListener("click",function(e){console.log("黄 捕获事件");
},true);
s3.addEventListener("click",function(e){console.log("蓝 捕获事件");
},true);
事件捕获与事件冒泡同时存在
- 这里记被点击的 DOM 节点为 target 节点,document 往 target 节点,捕获前进,遇到注册的捕获事件立即触发执行
- 到达 target 节点,触发事件
- 对于 target 节点上,是先捕获还是先冒泡则捕获事件和冒泡事件的注册顺序,先注册先执行
- arget 节点 往 document 方向,冒泡前进,遇到注册的冒泡事件立即触发
s1.addEventListener("click",function(e){console.log("红 冒泡事件");
},false);
s2.addEventListener("click",function(e){console.log("黄 冒泡事件");
},false);
s3.addEventListener("click",function(e){console.log("蓝 冒泡事件");
},false);
s1.addEventListener("click",function(e){console.log("红 捕获事件");
},true);
s2.addEventListener("click",function(e){console.log("黄 捕获事件");
},true);
s3.addEventListener("click",function(e){console.log("蓝 捕获事件");
},true);
应用:事件委托(也叫事件代理)
比如我想点击 ul 标签里面的 li 获取它的值, 有点人就会遍历去给每个 li 加一个事件监听
其实我们可以在 li 的父级加一个事件监听,这就相当于把事件监听委托给了 ul
我们点击 li 的时候是会打出值的
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
ul = document.getElementById('ur')
ul.addEventListener("click",function(e){console.log(e.target.innerText);
},false);