淺談JS事件機制與React事件機制

在JavaScript中,事件的觸發實質上是要通過三個階段:瀏覽器

  • 首先事件捕獲階段:事件由父元素一直傳遞到事件發生的元素
  • 執行目標對象自己的事件處理
  • 而後事件冒泡:事件從子元素向父元素冒泡

正由於事件在DOM的傳遞經歷這樣過程,爲行爲委託提供了可能,即行爲委託的實質就是將子元素事件的處理委託給父級元素處理。bash

  • React事件並無原生的綁定在真實的DOM上,而是使用了行爲委託方式實現事件機制,將事件最終都委託到最外層document,統一監聽,在冒泡階段處理,當掛載或者卸載組件時,在統一的事件監聽位置增長或者刪除對象。
  • React並無使用原生的瀏覽器事件,而是在基於Virtual DOM的基礎上實現了合成事件(SyntheticEvent),事件處理程序接收到的是SyntheticEvent的實例。
  • SyntheticEvent徹底符合W3C的標準,所以在事件層次上具備瀏覽器兼容性,與原生的瀏覽器事件同樣擁有一樣的接口,能夠經過stopPropagation()和preventDefault()相應的中斷。若是須要訪問當原生的事件對象,能夠經過引用nativeEvent得到。

另外注意不要將React事件和DOM原生事件混用,譬如常見的sidebar的點擊外部即隱藏的實現,阻止事件冒泡時,就要在真實DOM層面中去stopPropagation:ide

componentDidMount() {
  // 點擊body後隱藏sidebar
  document.body.addEventListener('click', e => {
    this.setState({
      showSidebar: false,
    });
  });
  
  // 點擊sidebar自己時,阻止click事件冒泡到body,則sidebar不會隱藏
  document.querySelector('.sidebar').addEventListener('click', e => {
    e.stopPropagation();
  })
}

componentWillUnmount() {
  document.body.removeEventListener('click');
  document.querySelector('.sidebar').removeEventListener('click');
}
複製代碼

或者經過原生事件對象中的target進行條件判斷:ui

componentDidMount() {
  document.body.addEventListener('click', e => {
    if (e.target && e.target.matches('div.sidebar')) {
      return;
    }
    
    this.setState({
      showSidebar: false,
    });
  });
}
複製代碼
相關文章
相關標籤/搜索