天天看點

解讀鴻蒙源碼: 鴻蒙“小程式”工作原理研究筆記

自從微信小程式出現以來,各種“小程式”如雨後春筍一般出現。事實證明小程式這種開發方式非常好,鴻蒙 JS UI 架構采用類似的方式也是在意料之中的。

一個小程式(在鴻蒙 OS 中,也就是 Ability)由多個頁面組成,每個頁面由三部分組成:

.hml 用來描述界面的元素

.css 用來描述界面的風格

.js 用來編寫處理事件邏輯

我們來看個例子:

index.hml

index.css

index.js

2. 工作原理

要了解它的工作原理,先研究一下編譯之後的代碼是非常重要的。上面的三個檔案,編譯之後會生成一個檔案,其位置在:./entry/build/intermediates/res/debug/lite/assets/js/default/pages/index/index.js

index.hml 變成了建立函數:

index.css 變成了 JSON 檔案。

這種處理方式很妙,把 JS 不擅長處理的 XML/CSS 轉換成了 JS 代碼和 JSON 對象,這個轉換由工具完成,避免了運作時的開銷。

在沒有研究編譯之後的代碼時,我嘗試在 ace/graphic 兩個包中尋找解析 HML 的代碼,讓我驚訝的是沒有找到相關代碼。看了這些生成的代碼之後才恍然大悟。

在 C++的代碼中,建立控件的過程如下:

調用 JS 的 _c 函數時,進入 C++的函數 RenderModule::CreateElement

RenderModule::CreateElement 的實作如下:

把 控件的 tag 轉換成控件的 ID
調用 ComponentFactory::CreateComponent 建立控件
調用控件的 Render 建立真正的控件和子控件。

那麼第一個_c 函數是在哪裡調用的呢?答案很明顯,進入一個頁面的時候,會調用 RenderPage 渲染頁面:

這裡會調用 JS 的 render 函數:

這裡的 renderFunction 又是哪個函數呢?這需要看看 ViewModel 的構造函數:

這裡的$render 是由 options 提供的,而 options 又是從哪裡來的呢?再來看看編譯後的代碼:

把 options.render 列印出來,可以看到

正是前面那個建立控件的函數。

從前面的代碼,很容易了解初始渲染時資料的綁定過程。比如 text 的 value 屬性從一個匿名函數擷取,它包裝了 xml 中些的表達式:

而運作時,資料變化時,需要監控匿名函數的值變化,變化時會調用下面這個函數,它負責更新控件的屬性。

在 initState 函數中,關注了 data 的變化:

條件渲染由_i 函數處理,它有兩個參數:

第一個參數是一個函數,決定是否進行渲染。

第二個參數是一個函數,決定如何進行渲染。

如:

編譯成:

C++中對應這個函數:

資料變化時,重新進行根據條件進行渲染,執行下面的函數:

關注資料變化的回調函數。

這個做法我覺得很有創意:

不需要搞虛拟 DOM 進行比較。

不需要重建立立整個 DOM。

繼續閱讀