反应点击事件冒泡“横向”,而不仅仅是“向上”

Posted

技术标签:

【中文标题】反应点击事件冒泡“横向”,而不仅仅是“向上”【英文标题】:React click event bubbling "sideways", not just "up" 【发布时间】:2017-12-02 12:41:30 【问题描述】:

我在组件中嵌套了点击事件处理程序:

class ListItem extends React.Component 
    ...
    render() 
        return (
            <div onClick=this.save>
              ...Content...
              <span onClick=this.onDeleteClick> (Delete)</span>
            </div>
        );
    
    ...

(完整的,本文底部的最小示例。)

此组件用作包含组件中的“列表项”。当我单击(Delete) 时,它会按预期触发onDeleteClick,这会回调父组件,从而导致组件从父组件中删除。正如预期的那样,点击事件然后开始冒泡。但是,它会“向上”冒泡到 父列表中的下一个组件。毕竟,原来的目标已经被删除处理程序删除了。

如果我将 e.stopPropagation() 添加到 onDeleteClick 处理程序的顶部,一切正常,但我只是想了解 为什么 click 事件被传递到一个完全不同的组件,只是为了确保那里没有任何其他确凿证据。

我目前的理论是,挂起的事件队列以某种方式被索引到虚拟 DOM 中,如果您在事件处理程序期间改变虚拟 DOM,冒泡事件可能会传递到虚拟 DOM 中的错误组件。我本来希望冒泡事件只是触发,而不是在完全不同的组件上触发。

这是怎么回事?还有其他见解吗?这是一个有缺陷的设计吗?如果有,有什么替代方案的建议吗?


这是一个显示问题的最小示例:https://codepen.io/mgalgs/pen/dRJJyB

这是固定版本:https://codepen.io/mgalgs/pen/KqZBKp

“修复”的完整差异是:

--- orig.jsx
+++ new.jsx
@@ -32,6 +32,7 @@
     

     onDeleteClick(e) 
+        e.stopPropagation();
         this.props.onDeleteClick(e);
     
 

【问题讨论】:

实际上,这真的很好奇:codepen.io/anon/pen/rwpZNK?editors=1111 --- 如果您检查 CodePen 控制台,它似乎正确地冒泡到正确的父级,但如果您检查开发者控制台,它会冒泡到错误的父母。 我怀疑因为 react 依赖于键,它实际上可能会将其推送到“下一个”元素,因为它现在占据了原始删除的元素 【参考方案1】:

+1 感谢您提出一个有趣的问题。

这种行为似乎与W3C's recommendations 一致:

从事件目标到树顶的 EventTargets 链 在事件的初始调度之前确定。如果 在事件处理、事件流期间对树进行修改 将根据树的初始状态进行。

这可能有助于解释这里发生的事情。 DOM 树似乎在气泡传播到父元素之前已被修改,此时事件将针对树中该位置的元素(如果有)。

在这种情况下,触发事件的元素会从树中移除。它不会冒泡到 next 元素,而是冒泡到现在已经在初始元素所在的元素集合中占据其位置的元素,如果有的话。

【讨论】:

知识增长!谢谢!我想关键点是:不要在事件处理程序中改变* DOM,除非你也阻止事件传播。 (* = 可能仅适用于删除事件树上的任何目标节点 实际上,更一般地说,也许我们可以说:不要在事件处理程序中使用setState,除非您满足以下一个:(1)您绝对知道它不会导致当前处理事件的任何目标被删除。 (2) 你停止了事件的传播。

以上是关于反应点击事件冒泡“横向”,而不仅仅是“向上”的主要内容,如果未能解决你的问题,请参考以下文章

jquery阻止事件冒泡

Javascript事件冒泡

微信小程序 - 事件绑定bind和catch 区别

JQuery阻止事件冒泡

移动端阻止事件冒泡需要注意!

事件委托(利用事件冒泡)