每天一个前端面试题之 DOM事件流
一、DOM事件流是什么?
首先明确一点,javascript和HTML的交互式通是事件完成。事件就是文档或浏览器窗口发生的一些特定的交互瞬间,事件流描述的是事件接收传播的过程、
二、DOM事件流的三个阶段
1.事件捕获阶段
事件捕获的思想是不太具体的DOM节点先先接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于:事件到达预定的节点之前就捕获它。
2.当前目标阶段
当前的目标节点正在处理事件的阶段。
3.事件冒泡
事件冒泡的思想是由最具体的元素(嵌套层次最深的那个DOM节点)接收,然后逐级向上传播到较为不具体的DOM节点。
有些事件是没有事件冒泡的,比如onblur,onfocus,onmouseenter,onmouseleave
阻止事件冒泡的方法:event.stopPropagation()
IE6、7、8使用 event.cancleBubble=true;
在addEventListener中还可以使用event.stopImmediatePropagation(),阻止事件冒泡并阻止该元素上同事件类型的监听器被触发。
下面图片有助于我们更好的理解DOM事件流的三个阶段。
图片来源:https://my.oschina.net/sevenhdu/blog/332014
三、事件委托
事件委托的依据是事件冒泡。
主要原理为:不给每个子节点单独设置事件监听器,而是将事件监听器设置在其父节点上。
适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。
四、例子
下面有一个有趣的例子,自己写一写代码分析一下会更清晰。
从外到内分别是盒子爷爷,盒子爸爸和盒子小明。
son.addEventListener("click", function (event) {
console.log("小明");
}, true);
father.addEventListener("click", function (event) {
console.log("爸爸");
}, true);
grantfather.addEventListener("click", function (event) {
console.log("爷爷1");
}, true);
grantfather.addEventListener("click", function (event) {
console.log("爷爷2");
});
grantfather.addEventListener("click", function (event) {
console.log("爷爷3");
event.stopImmediatePropagation();//阻止事件冒泡并阻止该元素上同事件类型的监听器被触发
}, true);
grantfather.addEventListener("click", function (event) {
console.log("爷爷4");
}, true);
点击小明,输出 爷爷1, 爷爷3。
分析:son.addEventListener的第三个属性设置为true,表示事件捕获,是由上到下的,所以先输出爷爷1,再输出爷爷3,然后爷爷3阻止了事件冒泡和该元素上的同类型事件监听器,所以到此就结束了。
点击爸爸,和点击小明的结果是一样的。
点击爷爷,输出 爷爷1, 爷爷3。分析也同上。
如果去掉event.stopImmediatePropagation();
点击小明,输出 爷爷1, 爷爷3,爷爷4,爸爸,小明,爷爷2.
因为爷爷2是在事件冒泡阶段,所以最后输出。
点击其他的也可以同理分析。
五、事件委托的优缺点
优点:1. 可以大量节省内存占用,减少事件注册。比如ul上代理所有li的click事件就很不错。
2. .可以实现当新增子对象时,无需再对其进行事件绑定,对于动态内容部分尤为合适
缺点:事件代理的常用应用应该仅限于上述需求,如果把所有事件都用事件代理,可能会出现事件误判。即本不该被触发的事件被绑定上了事件。