对于事件的传播机制,Netscape Communicator采用的是事件捕获(event capture),IE9、Safari、Chrome、Opera和Firefox采用的是事件冒泡(event bubbling),下面我们通过案例来具体理解,代码使用chrome浏览器进行测试,先给出HTML和CSS文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>理解事件冒泡与事件捕获</title>
<style>
html {
box-sizing: border-box;
}
*, *:before, *:after { box-sizing: inherit; }
div {
width:100%;
padding:50px;
}
.one {
background: red;
}
.two {
background:blue;
}
.three {
background:green;
}
</style>
</head>
<body class="bod">
<div class="one">外面:id为1
<div class="two">中间:id为2
<div class="three">里面:id为3
</div>
</div>
</div>
<p>请点击复选框控件</p>
<form>
<label for="id-checkbox">Checkbox</label>
<input type="checkbox" id="id-checkbox" name="checkbox" checked />
</form>
</body>
</html>
一、capture参数
在chrome中默认以冒泡的形式,capture为false,可以直接指定第三个参数为false,相当于{capture:false}
function logText(e) {
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click', logText));
点击id=one元素 : one;
点击id=2的元素 : two one
点击id=3的元素,three two one
function logText(e) {
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: true,
}));
点击id=one元素 : one;
点击id=2的元素 :one two
点击id=3的元素 : one two three
二、 e.stopPropagation():阻止捕获和冒泡阶段中当前事件的进一步传播
function logText(e) {
console.log(this.classList.value);
e.stopPropagation(); // one ; two ; three
}
divs.forEach(div => div.addEventListener('click', logText));
点击id=one元素 : one
点击id=2的元素 :two
点击id=3的元素 : three
function logText(e) {
console.log(this.classList.value);
e.stopPropagation();/
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: true,
}));
事件只会在第一个捕获的元素上面触发
点击id=one元素 : one
点击id=2的元素 :one
点击id=3的元素 : one
三、event.preventDefault():
(1)如果事件可取消,则取消该事件,而不停止事件的进一步传播。preventDefault 方法不会阻止该事件的进一步冒泡. event.stopPropagation 方法才有这样的功能.
document.querySelector("#id-checkbox").addEventListener("click", function(event){
alert("preventDefault会阻止该复选框被勾选.")
event.preventDefault();//无法勾选选项框
console.log(event.defaultPrevented);//true
//阻止该复选框被勾
}, false);
(2)使用passive:false来禁止e.preventDefault()的调用
document.querySelector("#id-checkbox").addEventListener("click", function(event){
event.preventDefault();//可以勾选选项框
console.log(event.defaultPrevented);//false
}, {passive:true});//Unable to preventDefault inside passive event listener invocation.
四、事件代理:
1、原理:事件冒泡,为外层元素指定一个事件处理程序,就可以管理某一类型的所有事件。
(1)event.target和event.currentTarget:在事件处理程序内部,对象 this 始终等于 currentTarget 的值,而 target 则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则 this、currentTarget 和 target包含相同的值:
(2)event.eventPhase :可以用来确定事件当前正位于事件流的哪个阶段。如果是在捕获阶
段调用的事件处理程序,那么eventPhase 等于1;如果事件处理程序处于目标对象上,则event-
Phase 等于2;如果是在冒泡阶段调用的事件处理程序,eventPhase 等于3。这里要注意的是,尽管
“处于目标”发生在冒泡阶段,但eventPhase 仍然一直等于2
function logText(e) {
console.log(e.currentTarget);
console.log(e.currentTarget === this);
console.log(e.target);
}
document.querySelector('.one').addEventListener('click',logText,false);
依次点击id为1、2、3的div控制台会输出以下数据:
下面通过使用{capture:true}参数了解event.eventPhrase,尽管“处于目标”发生在捕获阶段,但eventPhase 仍然一直等于2
function logText(e) {
console.log(e.currentTarget);
console.log(e.currentTarget === this);
console.log(e.target);
console.log(e.eventPhase);
}
document.querySelector('.one').addEventListener('click',logText,{capture:true});
依次点击id为1、2、3的div控制台会输出以下数据:
以上是本人对事件代理、事件捕获和事件代理的理解,不当之处,敬请指出:
本面试题为前端常考面试题,后续有机会继续完善。我是歌谣,一个沉迷于故事的讲述者。
欢迎一起私信交流。