React 事件踩坑(一)

问题描述

今天想要用react实现一个对话框的功能,这个对话框有一个特点就是在点击这个对话框的时候直接就能够使它隐藏,并且在对话框之外的任何东西都是可以点击的,并且能够及时的响应。比如下面的登陆对话框,我们在点击header上面的menu button的时候能够在显示left menu的同时将对话框给隐藏起来。

React 事件踩坑(一)_第1张图片

实现思路

实现思路很简单,就是在document.body上绑定一个click事件隐藏对话框,在对话框上绑定一个click事件来阻止自己的click的事情冒泡到document.body上。具体的实现代码如下:

class Dialog extends React.Component {
    constructor(...props){
        super(...props);

        [
            '_onBlurHandler',
            '_onClickHandler',

        ].forEach(func=>{
            this[func] = this[func].bind(this);
        });
    }

    _onBlurHandler(e){
        this.props.onBlur && this.props.onBlur(e);
    }

    _onClickHandler(e){
        e.nativeEvent.stopPropagation();
    }

    componentDidMount(){
        document.body.addEventListener('click', this._onBlurHandler, false);

    }

    componentWillUnmount(){
        document.body.removeEventListener('click', this._onBlurHandler, false);
    }


    render(){
        const className = [
            'dialog',
            this.props.className,   

        ].join(' ');

        return (
           <div 
              className={className}
              onClick={this._onClickHandler}>
              {this.props.children}
           div>
        );
    }
}

Dialog.propTypes = {
    onBlur: React.PropTypes.func
};

好简单有没有,在实现之前把宝宝乐的,so easy。可是实现调试缺吓死抱抱了,为毛点击dialog的时候,dialog会触发document.body上绑定的click事件呢 ?

问题分析及解决

按理论上说上面没有问题呀,怎么可能会错呢,好吧我们还是好好的调试一下吧,我们先来看一下dialog上面绑定的Click事件有哪些?

React 事件踩坑(一)_第2张图片

哎,怎么有两个事件呢,而且都是代理在document上,我们绑定的事件呢?其实很简单了,对于react的事件,不是直接绑定在元素上的,而是代理给document,这样做是为了提高效率。然后我们仔细想想为什么我们出错了,因为我们的事件是绑定在document.body上面的,所以在点击的时候,事件先冒泡给body,可是这样会触发_onBlurHandler函数的调用,这个函数中我实现了一个隐藏对对话框的功能,所以导致我结果错了。知道原因那个就好办了,把document.body换成document不就可以了的,哈哈,我是天才有没有。

componentDidMount(){
        document.addEventListener('click', this._onBlurHandler, false);
    }

    componentWillUnmount(){
        document.removeEventListener('click', this._onBlurHandler, false);
    }

赶快调试一下能不能正常工作,我去,怎么又出上了问题,对话框还是消失了。怎么回事呀,不是应该没问题了吗,问题又在哪里了,哎,心塞。

仔细想一下,因为事件都是绑定在document上的,那么上面阻止冒泡的代码不是没有用了,那我们应该怎么解决呢,哈哈哈,也很简单,其实就是把stopPropagation换成stopImmediatePropagation就行了,这两个函数的区别在于stopImmediatePropagation会在调用对应的回调函数之后屏蔽对应元素对应事件所有回调函数的调用,并且禁止冒泡,而stopPropagation函数只屏蔽冒泡,并不屏蔽自身的事件。

好了,调试一下,啊哈哈哈哈,终于成功了。发现react的坑还是蛮多的,慢慢踩吧,每天进步一点。

你可能感兴趣的:(javascript,react)