mpvue原理分析

爲何要作小程序框架?vue

  1. 組件機制
  2. 多端複用
 
小程序實現原理
 
數據驅動視圖更新;視圖交互觸發事件,事件響應函數修改數據再次觸發視圖更新
 
 
mpvue原理
 
jsBridge
vue.js和小程序的工做原理一致,能夠把小程序的功能託管給vue.js,在正確的時機將數據變動同步到小程序,從而達到開發小程序的目的。這樣,咱們能夠將精力聚焦在 Vue.js 上,參照 Vue.js 編寫與之對應的小程序代碼,小程序負責視圖層展現,全部業務邏輯收斂到 Vue.js 中,Vue.js 數據變動後同步到小程序,如圖2所示。如此一來,咱們就得到了以 Vue.js 的方式開發小程序的能力
 
 
生命週期關聯:
vue和小程序的數據彼此隔離,各有不一樣的更新機制。mpvue從生命週期和事件回調函數切入,在vue觸發數據更新時實現數據同步。小程序經過視圖層呈現給用戶、經過事件響應用戶交互,vue在後臺維護這數據的變動和邏輯。爲了實現數據的同步,mpvue修改了vue的runtime實現,在vue的生命週期中增長了更新小程序數據的邏輯。
 
事件代理機制:
用戶交互觸發的數據更新經過事件的代理機制完成。vue中,事件響應函數對應組件的method,vue自動維護了上下文環境。然而在小程序中沒有這種機制,vue執行環境中維護了一份實時虛擬DOM,這與小程序視圖層徹底對應,小程序組件上觸發事件後,只要找到虛擬DOM上對應的節點,觸發對應的事件就能夠了;另外一方面,vue事件響應若是觸發了數據更新,其生命週期函數更新將自動觸發,在此函數上同步更新數據。
 
 
事件代理機制源碼分析
 
對比小程序事件系統,mpvue事件系統和Dom事件系統
// 小程序 event 對象屬性(8 個)
 
["type", "timeStamp", "target", "currentTarget", "detail", "touches", "changedTouches", "_requireActive"]
 
// DOM event 對象屬性 / 方法(54 個)
 
["isTrusted", "screenX", "screenY", "clientX", "clientY", "ctrlKey", "shiftKey", "altKey", "metaKey", "button", "buttons", "relatedTarget", "pageX", "pageY", "x", "y", "offsetX", "offsetY", ..., "cancelable", "timeStamp", "srcElement", "returnValue", "cancelBubble", "path", "composedPath", "stopPropagation", "stopImmediatePropagation", "preventDefault", "initEvent"]
// mpvue event 對象屬性 / 方法(9 個)
 
["mp", "type", "timeStamp", "x", "y", "target", "currentTarget", "stopPropagation", "preventDefault"]
  1. 在mpvue生成的wxml中,全部事件都被hanleProxy的函數接管,在handleProxy進行處理後再去調用咱們寫的真正的事件處理函數。這個方法在initMp時,做爲小程序page的構造函數的一個選項,從而能夠在wxml中被正確調用

  1. handleProxy將小程序的event對象傳給handleProxyWithVue函數進行進一步處理
  2. handleProxyWithVue的做用

    (1) 從跟實例開始,根據comkey找出事件處理函數所在的mpvue示例(getVm)node

    (2) 經過遍歷找到的vm的vnode,結合eventid找到小程序事件對應的真是的事件處理函數(getHandle)json

    (3) 將小程序的event對象包裝成mpvue的event對象(getWebEventByMP),並添加了preventDafault和stopPropagation方法,可是preventDafault和stopPropagation方法是兩個空函數(noop),因此組織冒泡仍是得使用.stop修飾符經過compile編譯成catchEvent小程序

  1. 將包裝後的event對象(getWebEventByMP), 傳給真實的處理函數進行調用
 
(生成的wxml中綁定事件的節點都有data-comkeydata-eventid屬性,在一個事件觸發時,它們是被用來尋找事件對應的vm實例和對應的事件處理函數的)
 
 
 
 
原有的mpvue更新機制:
mpvue實現原理是基於Vue2.js,重寫platform部分代碼來實如今小程序環境下用Vue組件系統進行運行。在Vue的H5實現中,當咱們組件樹上的一個組件屬性更改後,會觸發整個樹的檢查更新,而後在新老dom樹對比算出最小改動後,同步到瀏覽器的真實dom,這個過程熟悉Vue的開發者很熟悉了,就是diff更新。
可是H5版的diff最後的瀏覽器runtime代碼是基於增刪dom節點API進行的,小程序又不提供增刪節點的功能,因此爲了能在小程序環境實現更新,原版mpvue對整個觸發更新檢查的V-dom樹都取值轉換成了小程序對應的JSON,經過setData()接口同步到視圖。這個過程在實際運行會形成setData的數據冗餘過大。經過代理updateDataToMP打日誌的方式咱們發現,v-dom樹上任意節點的任意屬性更改,會引起整棵樹的更新,一次形如this.a = 1的操做會引發O(N^2)量級的更新。真實在項目中監控到,一個10個組件左右構成的頁面,每次進行一次this.a=1數據更新,在$nextTick渲染時真實傳到小程序的數據大概在10k-20k。安卓真機上會形成大概200-300ms的渲染演示,肉眼能較明顯覺察。
 
新mpvue數據更新機制:
新版Mpvue在每次數據更新的時候,會在Vue監聽set方法,每次觸發屬性更新的時候把當前更新的屬性key放在當前V-dom的__keyPath屬性中。一次更新所有觸發後,在實際render過程當中遍歷keyPath屬性,只選擇更新的屬性放到json裏,調用Page.setData來進行更新操做。同時在Vue.$nextTick函數裏,觸發完全部的render更新後會清理掉所有keyPath,防止下次再更新又冗餘。經過這種操做,this.a=1能夠O(N^2)量級下降到O(1).上面例子中每次更新10k-20k的頁面,在業務中有好比用戶操做引發某個組件數字+1,關閉彈窗等操做時,更新量下降到幾個字節。安卓卡頓的問題也從框架角度完美解決
相關文章
相關標籤/搜索