mpvue小程式開發 - 生命週期梳理

騰訊IMWeb團隊發表於2018-11-02

轉自IMWeb社群,作者:llunnn,原文連結

最近在開發小程式,嘗試性地使用了一下mpvue框架。

mpvue 是一個使用 Vue.js 開發小程式的前端框架。框架基於 Vue.js 核心,mpvue 修改了 Vue.js 的 runtime 和 compiler 實現,使其可以執行在小程式環境中,從而為小程式開發引入了整套 Vue.js 開發體驗。

mpvue同時維護了Vue和小程式的兩套機制,因此需要對兩套機制進行關聯。這裡主要對mpvue的生命週期來進行一些梳理。

微信小程式生命週期

首先我們需要了解,微信小程式的生命週期:

App物件,主要有onLaunch, onShow和onHide。

Page物件,主要有onLoad, onShow, onReady, onHide和onUnload。

Vue到mpvue

mpvue的出現使得我們可以用書寫Vue例項的方式去宣告這兩種物件,並使得Vue例項相容小程式的生命週期。

Vue的生命週期主要體現在8個鉤子:beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed。

來對比一下Vue和mpvue的生命週期,看一下mpvue做出了什麼改變:

mpvue小程式開發 - 生命週期梳理

對比來看,mpvue主要是對created和beforeMount之間的過程做了改變。

在Vue中,這個階段主要作用是將template編譯為render函式:

mpvue小程式開發 - 生命週期梳理

而在mpvue中,對於App或Page元件(這裡的Is App or Page component應該要解釋為“是否為App或Page元件”),為他們初始化小程式的生命週期,並註冊App物件或Page物件:

mpvue小程式開發 - 生命週期梳理

這裡可以看出來,mpvue中,Vue和小程式生命週期鉤子觸發的基本順序是beforeCreate -> created -> onLaunch/onLoad -> onShow -> onReady -> beforeMount -> mounted -> ...

實踐驗證

這裡有一個入口頁面,包含一個通過wx.navigateTo跳轉到newPage的按鈕。

newPage中包含一個card元件,和一個通過wx.navigateBack跳轉回入口頁面的按鈕。

mpvue小程式開發 - 生命週期梳理

在App, newPage和card的各個生命週期鉤子輸出資訊,來觀察它們的觸發情況和順序。

在App被建立,跳轉到newPage前

mpvue小程式開發 - 生命週期梳理

我們可以觀察到,app物件首先被建立,觸發onLaunch和onShow。

在這之後,newPage被create。需要注意的是,此時我們還沒有跳轉到newPage,也就是說在mpvue中,無論頁面是否被訪問到,其Vue例項的beforeCreate和created都在app建立後就被觸發。

第一次跳轉到newPage並返回入口頁面

mpvue小程式開發 - 生命週期梳理

由於newPage頁面的beforeCreate和created已經提前被觸發過了,在呼叫了wx.NavigateTo跳轉到newPage時,先觸發小程式的生命週期,再觸發beforeMount,這時候開始建立子元件card的例項,按照beforeCreate -> created -> onLoad -> onReady -> beforeMount -> mounted 的順序觸發生命週期鉤子。(這裡元件的onShow為什麼沒有觸發..需要再深入探究一下)

在wx.navigateBack時,小程式的生命週期鉤子onUnload被觸發。但需要注意的是:Vue的生命週期鉤子beforeDestroy和destroyed並沒有被觸發,也就是說小程式中newPage的page物件被解除安裝了,但newPage和card的Vue例項並沒有被銷燬。

第二次跳轉到newPage並返回入口頁面

mpvue小程式開發 - 生命週期梳理

newPage和card都已經被create且沒有destroy,在再次wx.navigateTo時將直接從onLoad -> onShow -> onReady開始觸發,newPage的mount和update過程也會出發,而component之後update過程被觸發了。這裡可以發現,在onLoad之後還經過了幾個階段,才開始觸發Vue例項的生命週期鉤子,而上一次儲存在記憶體中的資料並沒有被destroy,因此在重新載入的過程中,Vue例項還儲存著上一次載入頁面時的資料。

開發時遇到的問題

遇到的問題主要是由create過程在頁面載入前就被統一觸發引起的。 在使用Vue時,經常在created鉤子中獲得新的data。因為此時對data的資料觀測已經被建立,但是頁面內容尚未被掛載,Vue例項可以觀測到data的變化並在檢視顯示出來之前改變其內容。

如果在mpvue中,我們想獲取頁面路由query中的資料,或是想在頁面建立時請求介面,我們可能會這樣考慮:

在created中獲取資料? 在mpvue中,created只被觸發一次,且在頁面建立前被觸發,也就是說query中的資料是無法獲得的,再次訪問頁面時如果資料發生了變化,created中的邏輯也並不會再次執行。

推遲到beforeMount? 從功能上說,在beforeMount獲取資料是沒有問題的。但由於頁面unload時沒有觸發destroy,在再次載入頁面時,Vue例項仍然儲存著前一次獲得的資料,而頁面的onLoad、onShow均在beforeMount之前被觸發,實踐時會發現,頁面在資料更新之前就會被顯示出來,舊的資料會在頁面中“一閃而過”。

在onLoad中獲取資料? 實踐證明這的確是一種最穩妥的方法,資料能被正確地設定,頁面也不會“閃”。 但是官方文件有這樣一句話: 除特殊情況外,不建議使用小程式的生命週期鉤子。 這裡大概是為了程式碼的移植性做考慮吧,不知道這裡算不算特殊情況呢。

使用computed? 為了避免使用小程式的生命週期鉤子,還可以考慮使用computed的來獲取query中的內容,而query需要在頁面onLoad之後才存在,這裡需要注意做一些判斷。

總結

從Vue過度到mpvue還是非常平滑的,特別是在有過小程式開發經驗的情況下。但是由於小程式本身和瀏覽器的差異,使得開發過程中會遇到一些難以理解的問題,將生命週期做一下梳理對更順利地進行開發是有一些好處的。

但是,從這裡也可以看到,對於開發小程式來說,mpvue實際上額外地維護了一套Vue的機制,並對小程式的事件、資料進行代理、同步,實際上這個過程可能會造成一些效能上的損耗。再加上mpvue目前還是存在一些缺陷,而小程式也支援了資料繫結、元件化開發,個人認為若是追求高質量的開發還是直接使用原生小程式更優吧~

相關文章