ReactJS SyntheticEvent stopPropagation() 仅适用于 React 事件吗?

IT技术 javascript jquery reactjs
2021-02-09 20:54:58

我正在尝试在 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();
    });
});
6个回答

React 使用带有单个事件侦听器的事件委托document来处理冒泡事件,例如本例中的“click”,这意味着无法停止传播;当您在 React 中与其交互时,真实事件已经传播。stopPropagation在 React 的合成事件上是可能的,因为 React 在内部处理合成事件的传播。

使用JSFiddle进行下面的修复。

在 jQuery 事件上react停止传播

使用Event.stopImmediatePropagation以防止你的其他(jQuery的在这种情况下)听众根被调用。它在 IE9+ 和现代浏览器中受支持。

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
  • 警告:侦听器按照它们被绑定的顺序被调用。React 必须在其他代码(此处为 jQuery)之前初始化才能使其工作。

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/01/14):澄清委托仅用于冒泡的事件。有关事件处理的更多详细信息,React 的源代码具有描述性注释:ReactBrowserEventEmitter.js

@ssorellen:澄清:React 是将其事件侦听器绑定在document还是根 React 组件上?链接的页面只是说:“在最顶层”,我采取意味着它不会document(但我无法弄清楚,如果这是连相关)。
2021-03-20 20:54:58
另请查看 Jim 的回答,其中建议将全局点击侦听器添加到window而不是documentstackoverflow.com/a/52879137/438273
2021-03-29 20:54:58
@FighterJet 这取决于事件类型。对于冒泡的事件,使用顶级委托。对于不冒泡的事件,React 必须侦听各种 DOM 节点。ReactBrowserEventEmitter.js 中有更详尽的描述:github.com/facebook/react/blob/...
2021-04-01 20:54:58
我为暂时的downvote 道歉。我需要它来提交错误报告,我已将其替换为赞成票 :)
2021-04-12 20:54:58

这仍然是一个有趣的时刻:

ev.preventDefault()
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();

如果您的函数由标签包装,请使用此构造

你是什​​么意思wrapped by tag你能举个例子吗?
2021-03-21 20:54:58
event.nativeEvent是正确答案;我能够composedPath()通过它使用:event.nativeEvent.composedPath()
2021-04-08 20:54:58
@JimmyLv 我是说 <div onClick=(firstHandler)> <div onClick=(secHandler)>active text</div> </div>
2021-04-12 20:54:58

值得注意的是(从这个问题),如果你将事件附加到documente.stopPropagation()不会有帮助。作为一种解决方法,您可以使用window.addEventListener()代替document.addEventListener,然后event.stopPropagation()将阻止事件传播到窗口。

非常感谢你!这正是我所拥有的,并且此解决方案有效。
2021-03-29 20:54:58

我能够通过将以下内容添加到我的组件来解决这个问题:

componentDidMount() {
  ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
    event.stopPropagation();
  }, false);
}
这将完全停止 SynteticEvents,因为 React 使用事件委托和文档上的单个事件侦听器来处理冒泡事件。
2021-03-18 20:54:58

来自React 文档: 下面的事件处理程序冒泡阶段的事件触发要为捕获阶段注册事件处理程序,请附加 Capture(强调)

如果您的 React 代码中有一个单击事件侦听器并且您不希望它冒泡,我认为您想要做的是使用onClickCapture而不是onClick. 然后,您将事件传递给处理程序并执行event.nativeEvent.stopPropagation()以防止本机事件冒泡到 vanilla JS 事件侦听器(或任何未响应的事件)。

谢谢,这就是 2021 年和 React 17 对我有用的方法。不过 onClickCapture={e => e.stopPropagation()} 就足够了,不必使用 event.nativeEvent 来停止传播到根。
2021-03-14 20:54:58