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

lof*_*ate 112 javascript jquery reactjs

我正在尝试在ReactJS组件中使用event.stopPropagation()来阻止点击事件冒泡并触发遗留代码中使用JQuery附加的单击事件,但似乎React的stopPropagation()仅停止传播到事件也附加在React中,而JQuery的stopPropagation()不会停止传播到React附带的事件.

有没有办法让stopPropagation()在这些事件中发挥作用?我写了一个简单的JSFiddle来演示这些行为:

http://jsfiddle.net/7LEDT/3/

/** @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();
    });
});
Run Code Online (Sandbox Code Playgroud)

Ros*_*len 150

React使用事件委托和单个事件监听器来document处理冒泡的事件,比如本例中的"click",这意味着无法停止传播; 当你在React中与它交互时,真实事件已经传播了.stopPropagation因为React在内部处理合成事件的传播,所以可以使用React的合成事件.

使用下面的修复工具JSFiddle:http://jsfiddle.net/7LEDT/6/

在jQuery事件上反应停止传播

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

stopPropagation: function(e){
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
},
Run Code Online (Sandbox Code Playgroud)
  • 警告:监听器按照绑定的顺序进行调用.必须在其他代码(这里是jQuery)之前初始化React才能使其正常工作.

jQuery在React事件上的停止传播

你的jQuery代码也使用事件委托,这意味着stopPropagation在处理程序中调用并不会停止任何事情; 事件已经传播到document,并且将触发React的侦听器.

// Listener bound to `document`, event delegation
$(document).on('click', '.stop-propagation', function(e){
    e.stopPropagation();
});
Run Code Online (Sandbox Code Playgroud)

为了防止传播超出元素,侦听器必须绑定到元素本身:

// Listener bound to `.stop-propagation`, no delegation
$('.stop-propagation').on('click', function(e){
    e.stopPropagation();
});
Run Code Online (Sandbox Code Playgroud)

编辑(2016/01/14):澄清说,授权必须仅用于冒泡的事件.有关事件处理的更多详细信息,React的源代码具有描述性注释:https://github.com/facebook/react/blob/b87aabd/packages/react-dom/src/events/ReactBrowserEventEmitter.js#L52-L85

  • @FighterJet这取决于事件类型.对于冒泡的事件,使用顶级委派.对于不冒泡的事件,React必须侦听各种DOM节点.ReactBrowserEventEmitter.js中包含更详尽的描述:https://github.com/facebook/react/blob/3b96650e39ddda5ba49245713ef16dbc52d25e9e/src/renderers/dom/client/ReactBrowserEventEmitter.js#L23 (2认同)

sen*_*tor 7

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

componentDidMount() {
  ReactDOM.findDOMNode(this).addEventListener('click', (event) => {
    event.stopPropagation();
  }, false);
}
Run Code Online (Sandbox Code Playgroud)

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

小智 7

仍然是一个有趣的时刻:

ev.preventDefault()
ev.stopPropagation();
ev.nativeEvent.stopImmediatePropagation();
Run Code Online (Sandbox Code Playgroud)

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

  • `event.nativeEvent` 是正确答案;我能够通过它使用`composedPath()`:`event.nativeEvent.composedPath()` (2认同)

Eri*_* R. 6

我昨天遇到了这个问题,所以我创建了一个React友好的解决方案.

查看react-native-listener.到目前为止,它运作良好.反馈意见.

  • `react-native-listener`使用`findDomNode`将被弃用https://github.com/yannickcr/eslint-plugin-react/issues/678#issue-165177220 (4认同)

小智 6

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


Nei*_*rdi 6

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

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

  • 谢谢,这就是截至 2021 年和 React 17 对我有用的方法。 onClickCapture={e =&gt; e.stopPropagation()} 就足够了,不必使用 event.nativeEvent 来停止向根的传播。 (4认同)

Che*_*wai 6

React 17 将事件委托给root而不是document,这可能会解决问题。更多细节在这里。你也可以参考我的博客