对于事件的传播机制,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控制台会输出以下数据:

以上是本人对事件代理、事件捕获和事件代理的理解,不当之处,敬请指出:

本面试题为前端常考面试题,后续有机会继续完善。我是歌谣,一个沉迷于故事的讲述者。

欢迎一起私信交流。

“睡服“面试官系列之各系列目录汇总(建议学习收藏)