冒泡与捕获事件


冒泡

点击大一点的最顶层的盒子的时候,优先处理了那个小盒子,而父盒子里面那个小盒子的话,后面才去加载,这样做在处理hover的时候容易触发区域改变有问题,详情见我的项目友情链接那个地方

当一个事件发生在一个元素上,它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。

假设我们有 3 层嵌套 FORM > DIV > P,它们各自拥有一个处理程序:

点击内部的 <p> 会首先运行 onclick

  1. 在该 <p> 上的。
  2. 然后是外部 <div> 上的。
  3. 然后是外部 <form> 上的。
  4. 以此类推,直到最后的 document 对象。

因此,如果我们点击 <p>,那么我们将看到 3 个 alert:pdivform

这个过程被称为“冒泡(bubbling)”,因为事件从内部元素“冒泡”到所有父级,就像在水里的气泡一样。

event.target 可能会等于 this —— 当点击事件发生在 <form> 元素上时,就会发生这种情况。

具体例子,想要实现鼠标移动到父div时,显示更大的子div浮层卡片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { useRef } from "react";


const LinkDetails = ({ post, getConfig, index }) => {
const tooltipRef = useRef(null);
const handleMouseOver = (e) => {
e.stopPropagation();
if (tooltipRef.current) {
tooltipRef.current.style.opacity = "1";
tooltipRef.current.style.visibility = "visible";
}
};
const handleMouseOut = (e) => {
if (tooltipRef.current) {
tooltipRef.current.style.opacity = "0";
tooltipRef.current.style.visibility = "hidden";
}
};
<div
className="flex flex-col space-y-0.5 flex-grow w-3/4 hover-trigger"
onMouseOver={(e) => handleMouseOver(e)}
onMouseOut={(e) => handleMouseOut(e)}
>
<h2 className="text-sm font-semibold leading-5 truncate">
{post.title}
</h2>
<p className="text-current text-xs truncate ">{post.description}</p>
<div
ref={tooltipRef}
className={classNames(
"w-full p-2 bg-gray-700/[.9] text-white text-sm rounded-md",
"absolute bottom-10 xl:left-[75px] left-[10px] z-[55]",
"opacity-0 visibility-hidden transition-opacity duration-300"
)}
>
{post.description}
</div>
</div>

捕获

事件处理的另一个阶段被称为“捕获(capturing)”。它很少被用在实际开发中,但有时是有用的。

DOM 事件标准描述了事件传播的 3 个阶段:

  1. 捕获阶段(Capturing phase)—— 事件(从 Window)向下走近元素。
  2. 目标阶段(Target phase)—— 事件到达目标元素。
  3. 冒泡阶段(Bubbling phase)—— 事件从元素上开始冒泡。
捕获图示

也就是说:点击 <td>,事件首先通过祖先链向下到达元素(捕获阶段),然后到达目标(目标阶段),最后上升(冒泡阶段),在途中调用处理程序。

总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>

<form>FORM
<div>DIV
<p>P</p>
</div>
</form>

<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
}
</script>

上面这段代码为文档中的 每个 元素都设置了点击处理程序,以查看哪些元素上的点击事件处理程序生效了。

如果你点击了 <p>,那么顺序是:

  1. HTMLBODYFORMDIV(捕获阶段第一个监听器):
  2. P(目标阶段,触发两次,因为我们设置了两个监听器:捕获和冒泡)
  3. DIVFORMBODYHTML(冒泡阶段,第二个监听器)。

文章作者: 悠然寂夏
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 悠然寂夏 !
评论
评论
评论
  目录