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


126

我试图在ReactJS组件中使用event.stopPropagation()来阻止单击事件冒泡并触发遗留代码中与JQuery关联的click事件,但是似乎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();
    });
});

9
React的实际事件侦听器也位于文档的根目录,这意味着click事件已经冒泡到根目录。您可以event.nativeEvent.stopImmediatePropagation用来阻止其他事件侦听器触发,但是不能保证执行顺序。
Ross Allen

3
实际上,stopImmediatePropagation声明事件侦听器将按照绑定的顺序调用。如果您的React JS在jQuery之前进行了初始化(就像在小提琴中一样),则停止立即传播将起作用。
罗斯·艾伦

React阻止jQuery监听器被调用:jsfiddle.net/7LEDT/5 jQuery不可能阻止React的调用,因为jQuery监听器后来绑定在您的小提琴中。
罗斯艾伦2014年

一种选择是在中设置您自己的jQuery事件处理程序componentDidMount,但是它可能以意外的方式干扰其他React事件处理程序。
道格拉斯

我意识到第二个例子肯定是.stop-propagation行不通的。您的示例使用事件委托,但是试图在元素处停止传播。侦听器需要绑定到元素本身:$('.stop-propagation').on('click', function(e) { e.stopPropagation(); });。这个小提琴阻止了所有传播,就像您正在尝试的那样:jsfiddle.net/7LEDT/6
Ross Allen

Answers:


165

React使用事件委派和单个事件侦听器来启动document冒泡的事件,例如本示例中的“单击”,这意味着无法停止传播;当您在React中与真实事件互动时,真实事件已经传播了。stopPropagation由于React在内部处理合成事件的传播,因此可以对React的合成事件进行处理。

使用下面的修补程序来工作JSFiddle

在jQuery事件上反应停止传播

使用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(但我无法弄清楚,如果这是连相关)。
user128216 '16

2
@FighterJet取决于事件类型。对于冒泡的事件,使用顶级委派。对于不会冒泡的事件,React必须侦听各种DOM节点。更彻底的说明包括在ReactBrowserEventEmitter.js:github.com/facebook/react/blob/...
罗斯·艾伦

我对临时降职表示歉意。我需要它来生成错误报告,并已将其替换为upvote :)
Glorfindel

还请查看吉姆的答案,这建议添加全局点击侦听器,window而不是documentstackoverflow.com/a/52879137/438273
jsejcksn

13

值得注意的是(从本期开始)如果您将事件附加到documente.stopPropagation()将无济于事。解决方法是,您可以使用window.addEventListener()代替document.addEventListener,然后event.stopPropagation()阻止事件传播到窗口。


非常感谢你!这正是我所拥有的,并且该解决方案有效。
Anh Tran

10

仍然是一个有趣的时刻:

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

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


1
event.nativeEvent是正确的答案;我能够composedPath()通过它使用:event.nativeEvent.composedPath()
jimmont '18

你是什么意思wrapped by tag?您能否提供一个例子?
JimmyLv19年

@JimmyLv我的意思是 <div onClick=(firstHandler)> <div onClick=(secHandler)>active text</div> </div>
罗马

7

通过将以下内容添加到我的组件中,我能够解决此问题:

componentDidMount() {
  ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
    event.stopPropagation();
  }, false);
}

2
这将完全停止SynteticEvents,因为React将事件委托与文档上的单个事件侦听器一起使用来冒泡事件。
Vakhtang


2

来自React文档:下面的事件处理程序由冒泡阶段中的事件触发。要为捕获阶段注册事件处理程序,请附加Capture。(添加了重点)

如果您在React代码中有一个click事件侦听器,并且不想让它突然冒泡,我想您要使用onClickCapture而不是onClick。然后,您将事件传递给处理程序,并event.nativeEvent.stopPropagation()进行处理,以防止本机事件冒泡至原始JS事件侦听器(或任何不响应的事件)。


0

更新:现在可以 <Elem onClick={ proxy => proxy.stopPropagation() } />


1
参见@RossAllen的答案。这不会阻止传播到祖先的本机DOM侦听器(jQuery使用)。
Ben Mosher

好吧,这是使用React组件的正确方法。劫持事件不是一个好主意。
埃里克·霍登斯基

如果其他事情失败了,那是因为您做错了其他事情
Eric Hodonsky

1
我同意这是通过React连接所有侦听器的正确方法,但这不是这里的问题。
Ben Mosher

那就是我……我将始终鼓励正确使用正确的方法,而不是使某人误入歧途,因为他们对问题有“解决方案”,这可能使他们将来感到悲伤。
埃里克·霍登斯基

0

一个快速的解决方法是使用window.addEventListener而不是document.addEventListener

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.