在JavaScript中,事件的觸發實質上是要經過三個階段:
- 首先事件捕獲階段:事件由父元素一直傳遞到事件發生的元素
- 執行目標物件本身的事件處理
- 然後事件冒泡:事件從子元素向父元素冒泡
正因為事件在DOM的傳遞經歷這樣過程,為行為委託提供了可能,即行為委託的實質就是將子元素事件的處理委託給父級元素處理。
- React事件並沒有原生的繫結在真實的DOM上,而是使用了行為委託方式實現事件機制,將事件最終都委託到最外層document,統一監聽,在冒泡階段處理,當掛載或者解除安裝元件時,在統一的事件監聽位置增加或者刪除物件。
- React並沒有使用原生的瀏覽器事件,而是在基於Virtual DOM的基礎上實現了合成事件(SyntheticEvent),事件處理程式接收到的是SyntheticEvent的例項。
- SyntheticEvent完全符合W3C的標準,因此在事件層次上具有瀏覽器相容性,與原生的瀏覽器事件一樣擁有同樣的介面,可以通過stopPropagation()和preventDefault()相應的中斷。如果需要訪問當原生的事件物件,可以通過引用nativeEvent獲得。
另外注意不要將React事件和DOM原生事件混用,譬如常見的sidebar的點選外部即隱藏的實現,阻止事件冒泡時,就要在真實DOM層面中去stopPropagation:
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進行條件判斷:
componentDidMount() {
document.body.addEventListener('click', e => {
if (e.target && e.target.matches('div.sidebar')) {
return;
}
this.setState({
showSidebar: false,
});
});
}
複製程式碼