React 事件冒泡

在React中,咱們能夠在建立element的時候,傳入事件和處理函數,這些事件會被作爲合成事件來處理,固然,有些時候,咱們也須要定義原生事件,好比給document綁定事件。有些狀況下,就須要經過阻止事件冒泡來實現預期的交互效果。下面是幾個簡單的demojavascript

Demo

好比有以下的代碼:java

import React from 'react'
class Demo1 extends React.Component{
    onClickInner(e){
        console.log('inner div')
    }
    onClickOuter(e){
        console.log('outer div')
    }
    render(){
        return <div onClick={this.onClickOuter}>
            <div onClick={this.onClickInner}>inner div</div>
        </div>
    }
}

當咱們點擊 inner div時,控制檯輸出結果:react

inner div
outer div

這兩個事件都是合成事件,在點擊時,兩個事件會依次冒泡到document,由統一的事件監聽器處理。若是但願阻止onClickOuter 觸發,能夠在onClickInner內調用e.stopPropagation()。須要注意的是,這裏的e是合成事件實例,調用stopPropagation 也只能阻止合成事件的冒泡。函數

假如咱們將onClickOuter 經過原生事件來綁定:this

class App extends React.Component {
    onClickInner(e) {
        e.stopPropagation();
        console.log("inner div");
    }
    onClickOuter(e) {
        console.log("outer div");
    }
    componentDidMount() {
        this.outer.onclick = this.onClickOuter;// 經過DOM 0級綁定
    }
    render() {
        return (
            <div ref={ref => (this.outer = ref)}>
                <div id='inner' onClick={this.onClickInner}>123</div>
            </div>
        );
    }
}

雖然在onClickInner內調用了 e.stopPropagation, 可是原生事件仍是會經過冒泡來觸發,並且會先於onClickInner, 控制檯輸出:code

outer div
inner div

這是由於onClickInner合成事件被觸發的時候,說明點擊事件已經經過冒泡傳遞到了document,在這個過程當中,便會通過外層的div,進而觸發該原生事件。這也說明了,合成事件的stopPropagation只能阻止合成事件的冒泡。即便咱們在這裏經過e.nativeEvent獲取到原生事件並調用stopPropagation,也無濟於事,由於上面已經說了,在該合成事件被觸發的時候,已經冒泡到了document.
那麼咱們該經過什麼方式來阻止原生事件onClickOuter被觸發呢:
既然在onClickInner處理不了,只能在onClickOuter內處理了:component

onClickOuter(e) {// 這裏e是原生事件
   if(e.target && e.target.id === 'inner'){
       return ;
   }
   console.log("outer div");
}

若是咱們將原生事件綁定在了document上:事件

class App extends React.Component {
    constructor(props) {
        super(props);
        // this.bindDocument();
    }
    onClickInner(e) {
        console.log("inner div");
    }
    componentDidMount() {
        this.bindDocument();
    }
    bindDocument() {
        document.addEventListener("click", function(e) {
            console.log("document");
        });
    }
    render() {
        return (
            <div id="inner" onClick={this.onClickInner}>
                123
            </div>
        );
    }
}

上面代碼中,在組件掛載完畢後,再給document綁定click事件,這時候,React合成事件已經註冊完成,當點擊時,document上的click事件會依據綁定順序的前後依次執行,因此控制檯會輸出:ip

inner div
document

若是但願阻止後綁定的事件觸發,能夠在onClickInner內調用stopImmediatePropagationelement

若是有多個相同類型事件的事件監聽函數綁定到同一個元素,當該類型的事件觸發時,它們會按照被添加的順序執行。若是其中某個監聽函數執行了 event.stopImmediatePropagation() 方法,則當前元素剩下的監聽函數將不會被執行。