react的事件機制

好久沒寫博客了,前段時間太忙以至於平時的積累都記錄在內網的wiki裏,趁着這幾天有空,將這段時間所積累的乾貨慢慢的分享出來,如果內容有不正確的地方,歡迎糾正。

本博客大概介紹一下react的事件機制,並給出整體的設計圖,但不涉及react底層的源碼結構分析。

現象:

demo1: <div onclick="handle()">ni</div>

demo2: render() { return <div onClick={this.handle}>ni</div> }

雖然兩個例子都是通過標籤內嵌的方式將click事件進行綁定,但其中的原理是不一樣的,demo1是採用原生的事件處理,demo2是採用react的合成事件機制處理;

合成事件:

對於jsx來說,是採用了類似於DOM0的事件綁定的方式進行處理,它會收到一個合成事件對象(synthicevent),該對象集成了原生事件對象的所有特性,而且還是事件冒泡機制,並且能支持stopPropagation和preventDefault兩種方法;

原生事件與合成事件的區別:

  1. 原生的事件綁定是採用小寫onclick,而react則是採用大寫onClick;
  2. 原生事件綁定的是一個js的字符串,而react採用的是一個函數的指針;

合成事件的實現機制:

事件機制原型圖:

clipboard.png

該圖大概的表示了react的事件機制的整體結構圖,接下來具體說說它裏面的原理。

  • 真正的監聽者:

對於react來說,雖然事件是綁定在v-dom中,但其實真正的監聽者只有一個,就是結構中最外層的document對象進行監聽,主要採用了事件冒泡的方式,將v-dom中觸發的事件包裝成一個合成事件,然後通過事件冒泡的方式,最終冒泡到最外層的document監聽和執行(就是事件委託);

clipboard.png

  • 事件註冊:

事件註冊是在組件生成的時候,將v-dom中所有的事件都對應的原生事件都註冊在document的監聽器中,例如onClick對應的原生事件是onclick,如果v-dom中有綁定了onClick,那麼就會將對應的onclick事件註冊在document中,整個註冊過程可以三個階段:

1) 將v-dom中所涉及到的綁定事件所對應的原生事件都在enqueuePutListener中綁定到document身上;

2) 將v-dom中所有事件的事件處理函數都存放在listenerBank中,存放的方式是以registrtionname和key作爲索引存放,其中registrtionname是事件名,key是instance的id值,所以形式是:

   listenerBank[registrtionname][key] = listener

這樣的好處是將可能要觸發的事件分門別類,以及將對應的listener也分門別類存放;爲了就是在事件觸發的時候,能從listenerBank中取出同類型的listener存放在dispatchListener中;

3) 最後將dispatchEvent作爲callback函數,放在addEventListener和removeEventListener裏面,等待事件的觸發;

  • 合成事件:

當事件觸發的時候,不會直接將原生的事件發送到最外層的document中,而是經過處理,將處理後的事件發送到document中;事件合成的經過:獲取原生事件,並通過原生事件的類型和所在組件的id值,在listenerBank中取出對應的listener函數,並存放在_dispatchListener隊列中,然後將該實例存放到_dispatchInstance隊列中,這樣一來,可以將同類型的事件函數都按照順序存放在_dispatchListener中,最後一同處理;

  • 事件發佈:

當事件觸發時,會先原生事件變成合成事件,然後傳遞到document中,然後document會通過dispatchEvent回調函數依次執行dispatchListener中同類型的事件監聽函數。

  • 整個設計圖:

clipboard.png

以上是對react的合成事件一個大概的介紹,裏面還有很多細節和原理沒說到,有興趣的同學可以進一步研究一下源碼的細節。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章