1. 程式人生 > >react中button上繫結react事件觸發原生body上繫結的事件

react中button上繫結react事件觸發原生body上繫結的事件

情景再現

需求:在Web頁面中新增一個使用移動裝置掃描二維碼的功能,在點選按鈕時顯示二維碼(在點選按鈕二維碼消失),點選非二維碼區域時將其隱藏起來。

出現問題:點選按鈕二維碼顯示之後,在點選按鈕,二維碼一直顯示,不會消失

分析原因:React合成事件系統的委託機制,依賴事件的冒泡機制完成委派,在點選按鈕時,同時觸發了body上繫結的事件

出錯程式碼: 

class QrCode extends Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.handleClickQr = this.handleClickQr.bind(this);
        this.state = {
            active: false,
        };
    }
    componentDidMount() {
        debugger
        document.body.addEventListener('click', e => {
            this.setState({
                active: false
            });
        });
        //  不要將合成事件與原生事件混用
        document.querySelector('.code').addEventListener('click', e => {
            e.stopPropagation();
        })
    }
    componentWillUnmount() {
        document.body.removeEventListener('click');
        document.querySelector('.code').removeEventListener('click');
    }
    handleClick() {
        this.setState({
            active: !this.state.active,
        });
    }
    render() {
        return (
            <div className="qr-wrapper">
                <button className="qr" >二維碼</button>
                <div
                    className="code"
                    style={{display:this.state.active ? 'block' : 'none'}}
                    {onClick={this.handleClickQr}
                >
                    <img src={require('./a.jpg')} />
                </div>
            </div>
        );
    }
}

修改:不要將合成事件與原生事件混用,都改為原生事件

class QrCode extends Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.state = {
            active: false,
        };
    }
    componentDidMount() {
        document.body.addEventListener('click', e => {
            this.setState({
                active: false
            });
        });
        document.querySelector('.qr').addEventListener('click', e => {
            this.setState({
                active: !this.state.active,
            });
            //  必須加上阻止事件冒泡
            e.stopPropagation();
        })
        //  不要將合成事件與原生事件混用
        document.querySelector('.code').addEventListener('click', e => {
            e.stopPropagation();
        })
    }
    componentWillUnmount() {
        document.body.removeEventListener('click');
        document.querySelector('.code').removeEventListener('click');
        document.querySelector('.qr').removeEventListener('click');
    }
    render() {
        return (
            <div className="qr-wrapper">
                <button className="qr" >二維碼</button>
                <div
                    className="code"
                    style={{display:this.state.active ? 'block' : 'none'}}
                >
                    <img src={require('./a.jpg')} />
                </div>
            </div>
        );
    }
}