小编典典

React和jQuery事件处理程序的顺序错误

reactjs

我正在创建显示在屏幕顶部的菜单。当用户单击带有很多链接的菜单项div之一时。我将无法通过单击另一个菜单项(没有问题,已经实现)来隐藏此div,而且也无法通过单击该div和menuitems以外的其他任何位置来隐藏它。

我听说了两种解决方案:

  • 显示菜单后面并覆盖整个屏幕的不可见div,并向其中添加单击处理程序。
  • 将事件处理程序附加到document.body。

第一个对我不好,因为该div会覆盖页面上的链接,我希望即使单击menuitem并出现相应的div后,它们也可以被单击。所以我尝试了第二个灵魂。但是问题在于,主体上的jquery
click处理器在我组件的处理器之前被触发。我不知道如何使它首先调用我的组件处理程序,然后阻止事件传播。

这是代码和js小提琴:

/** @jsx React.DOM */
var Menu = React.createClass({
    click: function(e) {
        console.log('component handled click - should be called before jquery one and prevent jquery handler from running at all');
        e.stopPropagation();
    },
    render: function(){
    console.log("component renders");
        return (
            <div>
                <div>| MenuItem1 | MenuItem2 | MenuItem 3 |</div>
                <br />
                <div className="drop">
                    MenuItem 1 (This div appears when you click menu item)
                    <ul>
                        <li><a href="#" onClick={this.click}>Item 1 - when I click this I don't want document.body.click to fire</a></li>
                        <li><a href="#" onClick={this.click}>Item 1 - when I click this I don't want document.body.click to fire</a></li>
                    </ul>
                </div>
            </div>
        );
    }
});

React.renderComponent(<Menu />, document.getElementById("menu"));

$(document).ready(function() {
    console.log('document is ready');
    $("body").click(function() {
        console.log('jquery handled click - should not happen before component handled click');
    });
});

http://jsfiddle.net/psonsx6j/

运行控制台之前先启动控制台以解释问题


阅读 212

收藏
2020-07-22

共1个答案

小编典典

所以我解决了。当您使用jQuery将事件处理程序添加到文档时,将首先触发该事件处理程序。因此,您无法捕获事件并阻止事件的传播。但是,当您将处理程序与document.addEventlistener附加在一起时,此处理程序将被最后调用,您将有机会做出响应:)以单击React组件。

我修改了Mike的代码以使其工作(http://jsfiddle.net/s8hmstzz/):

/** @jsx React.DOM */
var Menu = React.createClass({
    getInitialState: function() {
        return {
            show: true
        }
    },
    componentDidMount: function() {
        // when attaching with jquery this event handler is run before other handlers
        //$('body').bind('click', this.bodyClickHandler);
        document.addEventListener('click', this.bodyClickHandler);
    },
    componentWillUnmount: function() {
        //$('body').unbind('click', this.bodyClickHandler);
        document.removeEventListener('click', this.bodyClickHandler);
    },
    anchorClickHandler: function(e) {
        console.log('click on anchor - doing some stuff and then stopping propation');
        e.stopPropagation();
        e.nativeEvent.stopImmediatePropagation();
    },
    bodyClickHandler: function(e) {
        console.log('bodyclickhandler');
        this.setState({show: false})
    },
    clickHandler: function(e) {
        // react to click on menu item
    },
    preventEventBubbling: function(e) {
        console.log('click on div - stopping propagation');
        e.stopPropagation();
        e.nativeEvent.stopImmediatePropagation();
    },
    render: function() {
        return (
            <div>
                <a href="#" onClick={this.anchorClickHandler}>Link - will stop propagation</a>
                <div id="menudrop" onClick={this.preventEventBubbling} style={{display: this.state.show ? 'block' : 'none'}}>
                    <ul>
                        <li onClick={this.clickHandler}>Menu Item</li>
                    </ul>
                </div>
            </div>
        )
    }
});

React.renderComponent(<Menu />, document.getElementById('menu'));

启动控制台,然后单击div,anchor和body以查看其工作原理。我不知道为什么使用addEventListener而不是jQuery会更改触发的事件处理程序的顺序。

2020-07-22