前言
為什麼會想寫這篇是因為我之前在SPA寫全域event的時候需要在離開頁面時需要清除添加在全域的event,打個比方我需要在特定的頁面在某些情況下禁止Y軸的scroll發生但是在離開該頁面後,要能夠讓scroll回到預設值。
因為我原先是在created hook 在 window.onresize 添加 scroll 控制的function 最後在 beforeDestroy hook 的時候刪除該頁面在 window.onresize 添加的function 。
但是我還有其他頁面也會針對會對 window.onresize 添加 function ,也同樣是在created hook 的時候添加,這時候會發現當兩個都有 window.onresize 添加 function 的頁面互相跳轉時,就會出現問題,問題的原因便是beforeDestroy的觸發時間點。
範例
我寫了一個簡單的DEMO
透過觀察各個component在呼叫hook時的優先順序,做一個理解
beforeRouteLeave // a.vue → b.vue
↓
beforeEach
↓
beforeRouteEnter // a.vue → b.vue
↓
afterEach
↓
beforeUpdate // App.vue
↓
beforeCreate // b.vue
↓
created // b.vue
↓
beforeMount // b.vue
↓
beforeCreate // d-child.vue
↓
created // d-child.vue
↓
beforeMount // d-child.vue
↓
beforeDestroy // a.vue
↓
beforeDestroy // c-child.vue
↓
destroyed // c-child.vue
↓
destroyed // a.vue
↓
mounted // d-child.vue
↓
mounted // b.vue
↓
updated // App.vue
簡單來說大概就是這樣的一個順序,頁面跳轉時先觸發的是
vue-router 的 hook
beforeRouteLeave // a.vue → b.vue
↓
beforeEach
↓
beforeRouteEnter // a.vue → b.vue
↓
afterEach
忽略App.vue不看,之後會先創建要跳轉到的頁面到beforeMount為止
beforeCreate // b.vue
↓
created // b.vue
↓
beforeMount // b.vue
再來是創建被 import 的 component ,一樣是到beforeMount為止,如果有孫以下的component以此類推
beforeCreate // d-child.vue
↓
created // d-child.vue
↓
beforeMount // d-child.vue
銷毀跳轉前的頁面,假如有 import 的 component ,一旦到beforeDestroy為止
↓
beforeDestroy // a.vue
再銷毀跳轉前的頁面 import 的 component ,一樣到beforeDestroy為止,如果有孫以下的component一樣以此類推
↓
beforeDestroy // c-child.vue
然後從最尾端的component開始執行destroyed
↓
destroyed // c-child.vue
全部import 的component 都 destroyed 完後才會執行父 component 的destroyed
↓
destroyed // a.vue
跳轉前頁面都銷毀完後,從創建的component最底端開始執行mounted
↓
mounted // d-child.vue
要跳轉的頁面所 import 的 component都創建完後,最後才執行父 component 的 mounted
↓
mounted // b.vue
總結
透過上面所展示的範例可以知道,如果有針對各個頁面所使用的全域event最好是到mounted在添加,避免添加後因為執行前一個畫面的beforeDestroy倒置又把event清空的情況發生。
使用soure
DEMO Soure
各位有興趣可以自己試看看。
環境
OS:Win 10
vue:2.6.11
vue-router:3.5.1