ReactJS SyntheticEvent stopPropagation() 仅适用于 React 事件?
Posted
技术标签:
【中文标题】ReactJS SyntheticEvent stopPropagation() 仅适用于 React 事件?【英文标题】:ReactJS SyntheticEvent stopPropagation() only works with React events? 【发布时间】:2014-08-16 10:15:26 【问题描述】:我正在尝试在 ReactJS 组件中使用 event.stopPropagation() 来阻止单击事件冒泡并触发在遗留代码中附加到 JQuery 的单击事件,但似乎 React 的 stopPropagation() 仅停止传播到也附加在 React 中的事件,并且 JQuery 的 stopPropagation() 不会停止传播到 React 附加的事件。
有什么方法可以让 stopPropagation() 在这些事件中工作?我写了一个简单的JSFiddle 来演示这些行为:
/** @jsx React.DOM */
var Propagation = React.createClass(
alert: function()
alert('React Alert');
,
stopPropagation: function(e)
e.stopPropagation();
,
render: function()
return (
<div>
<div onClick=this.alert>
<a href="#" onClick=this.stopPropagation>React Stop Propagation on React Event</a>
</div>
<div className="alert">
<a href="#" onClick=this.stopPropagation>React Stop Propagation on JQuery Event</a>
</div>
<div onClick=this.alert>
<a href="#" className="stop-propagation">JQuery Stop Propagation on React Event</a>
</div>
<div className="alert">
<a href="#" className="stop-propagation">JQuery Stop Propagation on JQuery Event</a>
</div>
</div>
);
);
React.renderComponent(<Propagation />, document.body);
$(function()
$(document).on('click', '.alert', function(e)
alert('Jquery Alert');
);
$(document).on('click', '.stop-propagation', function(e)
e.stopPropagation();
);
);
【问题讨论】:
React 的实际事件监听器也在文档的根目录,这意味着点击事件已经冒泡到根目录。您可以使用event.nativeEvent.stopImmediatePropagation
来阻止其他事件侦听器触发,但不保证执行顺序。
其实stopImmediatePropagation
声称事件监听器会按照绑定的顺序被调用。如果你的 React JS 在你的 jQuery 之前被初始化(就像它在你的小提琴中一样),停止立即传播将起作用。
React 阻止调用 jQuery 侦听器:jsfiddle.net/7LEDT/5 jQuery 无法阻止调用 React,因为 jQuery 侦听器稍后会在您的小提琴中绑定。
一种选择是在 componentDidMount
中设置您自己的 jQuery 事件处理程序,但它可能会以意想不到的方式干扰其他 React 事件处理程序。
我意识到.stop-propagation
上的第二个示例一定行不通。您的示例使用事件委托,但试图在元素处停止传播。侦听器需要绑定到元素本身:$('.stop-propagation').on('click', function(e) e.stopPropagation(); );
。这个小提琴可以防止像您尝试的所有传播:jsfiddle.net/7LEDT/6
【参考方案1】:
React 在document
上使用带有单个事件侦听器的事件委托来处理冒泡事件,例如本例中的“点击”,这意味着无法停止传播;当你在 React 中与它交互时,真实的事件已经传播了。 stopPropagation
React 的合成事件是可能的,因为 React 在内部处理合成事件的传播。
使用JSFiddle 进行下面的修复。
在 jQuery 事件上反应停止传播
使用Event.stopImmediatePropagation
防止调用根上的其他(在本例中为jQuery)侦听器。它在 IE9+ 和现代浏览器中受支持。
stopPropagation: function(e)
e.stopPropagation();
e.nativeEvent.stopImmediatePropagation();
,
警告:侦听器按绑定顺序调用。必须在其他代码(此处为 jQuery)之前初始化 React 才能使其正常工作。
jQuery 停止 React 事件的传播
您的 jQuery 代码也使用事件委托,这意味着在处理程序中调用 stopPropagation
不会停止任何事情;事件已经传播到document
,React 的监听器会被触发。
// Listener bound to `document`, event delegation
$(document).on('click', '.stop-propagation', function(e)
e.stopPropagation();
);
为了防止传播到元素之外,监听器必须绑定到元素本身:
// Listener bound to `.stop-propagation`, no delegation
$('.stop-propagation').on('click', function(e)
e.stopPropagation();
);
编辑(2016 年 1 月 14 日): 澄清委派必须仅用于冒泡事件。有关事件处理的更多详细信息,React 的源有描述性 cmets:ReactBrowserEventEmitter.js。
【讨论】:
@ssoellen:澄清:React 是否将其事件侦听器绑定在document
或根 React 组件上? linked page 只是说“在顶层”,我认为它不是 document
(但我不知道这是否相关)。
@FighterJet 这取决于事件类型。对于冒泡的事件,使用***委托。对于不冒泡的事件,React 必须监听各种 DOM 节点。 ReactBrowserEventEmitter.js 中包含更详尽的描述:github.com/facebook/react/blob/…
我对临时投反对票表示歉意。我需要它来报告错误,我已经用赞成票代替了它:)
还可以查看 Jim 的回答,它建议将全局点击侦听器添加到 window
而不是 document
:***.com/a/52879137/438273【参考方案2】:
这仍然是一个有趣的时刻:
ev.preventDefault()
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
如果你的函数被标签包裹,请使用这个结构
【讨论】:
event.nativeEvent
是正确答案;我可以通过它使用composedPath()
:event.nativeEvent.composedPath()
wrapped by tag
是什么意思?你能举个例子吗?
@JimmyLv 我的意思是<div onClick=(firstHandler)> <div onClick=(secHandler)>active text</div> </div>
【参考方案3】:
值得注意(来自this issue),如果您将事件附加到document
,e.stopPropagation()
将无济于事。作为一种解决方法,您可以使用window.addEventListener()
代替document.addEventListener
,然后event.stopPropagation()
将阻止事件传播到窗口。
【讨论】:
非常感谢!这正是我所拥有的,并且此解决方案有效。【参考方案4】:我能够通过将以下内容添加到我的组件来解决此问题:
componentDidMount()
ReactDOM.findDOMNode(this).addEventListener('click', (event) =>
event.stopPropagation();
, false);
【讨论】:
这将完全停止 SynteticEvents,因为 React 使用事件委托和文档上的单个事件侦听器来处理冒泡事件。【参考方案5】:来自React documentation: 下面的事件处理程序由冒泡阶段的事件触发。要为捕获阶段注册事件处理程序,请追加捕获。 (强调)
如果您的 React 代码中有一个单击事件侦听器并且您不希望它冒泡,我认为您想要做的是使用 onClickCapture
而不是 onClick
。然后您将事件传递给处理程序并执行event.nativeEvent.stopPropagation()
以防止本机事件冒泡到普通 JS 事件侦听器(或任何没有反应的东西)。
【讨论】:
谢谢,截至 2021 年和 React 17,这对我有用。 onClickCapture=e => e.stopPropagation() 就足够了,不必使用 event.nativeEvent 来停止传播到根。【参考方案6】:React 17 将事件委托给 root
而不是 document
,这可能会解决问题。
更多详情here。
也可以参考my blog。
【讨论】:
几个月前,我在文档上有一个监听器,即使在调用event.stopPropagation()
后仍会收到 mousedown 事件(我依赖于这种行为),但注意到在我更新后它不再被调用很多图书馆。我怀疑原因是 ReactJS 的更新,您的回答现在证实/解释了它。【参考方案7】:
我昨天遇到了这个问题,所以我创建了一个对 React 友好的解决方案。
查看react-native-listener。到目前为止,它运行良好。感谢您的反馈。
【讨论】:
react-native-listener
使用 findDomNode
将被弃用 github.com/yannickcr/eslint-plugin-react/issues/…
投反对票,因为答案不适合推向市场或提供不能补充完整答案的外部解决方案。【参考方案8】:
更新:你现在可以<Elem onClick= proxy => proxy.stopPropagation() />
【讨论】:
见@RossAllen 的回答。这不会阻止传播到祖先的本机 DOM 侦听器(jQuery 使用)。 如果您使用的是 react 组件,那么这是正确的方法。劫持事件不是一个好主意。 如果其他事情失败了,那是因为你做错了其他事情 我同意,如果您的所有听众都通过 React 附加,这是正确的方法,但这不是这里的问题。 这只是我...我将始终鼓励正确使用正确的方法,而不是通过一种可能导致他们未来悲伤的工作而将某人误入歧途,因为他们有一个“解决方案”问题。【参考方案9】:一种快速的解决方法是使用window.addEventListener
而不是document.addEventListener
。
【讨论】:
以上是关于ReactJS SyntheticEvent stopPropagation() 仅适用于 React 事件?的主要内容,如果未能解决你的问题,请参考以下文章