Twlig / issuesBlog

MIT License
3 stars 0 forks source link

冒泡与捕获 #19

Open Twlig opened 2 years ago

Twlig commented 2 years ago

当点击一个按钮时,实际上不光点击了这个按钮,还点击了它的容器以及整个页面。那么如何获取事件的发生先后顺序,就反映了事件流。

事件流描述了页面接收事件的顺序。有事件冒泡事件捕获两种。

事件冒泡

事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。

如:

<!DOCTYPE html> 
<html> 
<head> 
 <title>Event Bubbling Example</title> 
</head> 
<body> 
 <div id="myDiv">Click Me</div> 
</body> 
</html>

在点击页面中的<div>元素后,click 事件会以如下顺序发生:

1. <div>
2. <body>
3. <html>
4. document

<div>元素,即被点击的元素,最先触发 click 事件。然后,click 事件沿 DOM 树一路向上,在经过的每个节点上依次触发,直至到达 document 对象。

事件捕获

最不具体的节点最先收到事件,而最具体的节点最后收到事件。事件捕获实际上是为了在事件到达最终目标 前拦截事件

如果前面的例子使用事件捕获,则点击<div>元素会以下列顺序触发 click 事件:

1. document
2. <html>
3. <body>
4. <div>

在事件捕获中,click 事件首先由 document 元素捕获,然后沿 DOM 树依次向下传播,直至到达实际的目标元素<div>

通常建议使用事件冒泡,特殊情况下可以使用事件捕获。

事件流

DOM2 Events 规范规定事件流分为 3 个阶段:事件捕获、到达目标和事件冒泡。

image

注意:

由于存在事件冒泡,注册点击事件的顺序无关,只和事件冒泡的顺序有关,从内到外

document.body.onclick = function(event) { 
 console.log("Body clicked"); 
};
btn.onclick = function(event) { 
 console.log("Clicked"); 
}; 
//Clicked
//Body clicked     
//事件触发和注册点击事件的顺序无关,只和事件冒泡的顺序有关,从内到外,先btn触发,再是body

插播一个阻止冒泡的方法stopPropagation()

let btn = document.getElementById("myBtn"); 
btn.onclick = function(event) { 
 console.log("Clicked"); 
 event.stopPropagation();     //阻止事件冒泡,body点击事件无法触发
}; 
document.body.onclick = function(event) { 
 console.log("Body clicked"); 
};
//Clicked

补充:

大多数事件都支持冒泡,但是还有少数事件不支持:

  1. UI事件:load、unload、 scroll、resize
  2. 焦点事件:blur、focus
  3. 鼠标事件:mouseleave、mouseenter

这些事件仅发生于自身上,而它的任何父节点上的事件都不会产生,所有不会冒泡。