利用stopPropagation防止冒泡来阻断交互

97 阅读3分钟

✊不积跬步,无以至千里;不积小流,无以成江海

今天又遇见了一个新问题,感觉是可以深挖一下的。写一篇笔记记录一下。

问题描述

在实现能够通过单击召唤/隐藏,以及3s自动隐藏的时候,发现当对上方文件栏进行操作的时候也会触发单击召唤/隐藏。在已经将这个div作为ref添加到event事件里面的时候,依旧不能够解决这个bug。

解决之后期待的效果如下:

遇见这个问题的原因

这是因为在 React 组件中,直接为包含子组件的 div 引用并不会自动包含子组件的 DOM 元素。也就是说,即便 声明在 videoTitleRef 所引用的 div 内部,React 并不保证该子组件的 DOM 元素会包含在父组件的引用中。

要解决这个问题最终采用的方案:

事件传播停止:

在 DropDown4image 组件内部阻止事件传播,即通过 stopPropagation 方法来防止点击事件冒泡到父组件。

原理解释

在 JavaScript 中,事件传播包括三个阶段:

  1. 捕获阶段(Capturing Phase):事件从最外层元素向目标元素传播,检查是否有监听器捕获该事件。
  2. 目标阶段(Target Phase):事件到达目标元素并触发目标元素的事件监听器。
  3. 冒泡阶段(Bubbling Phase):事件从目标元素冒泡向最外层元素,检查是否有监听器捕获该事件。

默认情况下,事件会经历从捕获到冒泡的全部阶段。也就是说,当你在某个元素上触发一个事件(例如点击事件),这个事件将会先从最外层进入到该元素(捕获阶段),然后在该元素本身触发(目标阶段),最后再从该元素向最外层传播(冒泡阶段)。因此,在父组件添加的事件监听器也会被激活。

stopPropagation 方法的作用是在事件传播时立即阻止事件从目标元素冒泡到父元素,从而避免父元素的事件处理函数被触发。具体来说,它能防止事件在冒泡阶段传递给父级元素的事件监听器。

使用 stopPropagation 的实际应用

假设我们不使用 stopPropagation

  1. 用户点击 <DropDown4image /> 元素。
  2. 触发 <DropDown4image /> 内的点击事件处理函数。
  3. 由于事件会冒泡,事件会继续传播到其父元素(<div ref={videoTitleRef}>)。
  4. 最终传播到 document,触发 handleClickOutside 函数。

使用 stopPropagation 后:

  1. 用户点击 <DropDown4image /> 元素。
  2. 触发 <DropDown4image /> 内的点击事件处理函数。
  3. 由于 stopPropagation 方法被调用,事件不会冒泡到父元素。
  4. 因此,handleClickOutside 函数中的外部点击检测将不会被触发。

其他可行的办法:

在DropDown4imag组件内部封装一个ref:

并同时为 DropDown4image 组件增加 forwardRef,让它可以接受来自父组件的 ref。