小程序對組件化的“支持”情況微信小程序(以下簡稱“小程序”,版本)雖然默認定義了很多有用的組件,但是在開發小程序過程中,往往需要自定義業務組件。而小程序開發者文檔中卻未對自定義組件給出很好的解決方案或 ...
微信小程序(以下簡稱“小程序”,版本)雖然默認定義了很多有用的組件,但是在開發小程序過程中,往往需要自定義業務組件。
而小程序開發者文檔中卻未對自定義組件給出很好的解決方案或示例。
猜其原因可能有兩方面:
微信的組件化,總體而言,目標就是把具有特定功能和樣式的wxml、wxss、js(可選)文件抽取出來,以便不同頁面之間進行復用。
我們從實現上來考慮是否可行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// tab component - |- tab.wxml |- tab.js |- tab.wxss // tab.wxss .tab { ... } .tab .itme { ... } ... |
因為我們采用了include的方式共享了作用域,在簡單頁面的情況這種方式也不會出現什么問題,如果變量名或事件名被占用的時候換一個就好了。
但是在頁面引用多個組件的情況下如何保證它們之間不產生沖突?你可能想到了用老辦法命名隔離,組件內部變量和事件添加組件前綴用來和其它組件區分。
OK,在組件名不重復的情況下這是可行的。但是如果一個組件要同時觸發自身內部事件和父頁面事件就不是這么簡單了。
所以我們需要解決的一個關鍵問題是:組件如何隔離作用域,并暴露屬性或接口(函數)給頁面或其它組件?
我們在探索組件化實現方式時,有一個第三方模塊wepy脫穎而出。star數量超過了1k,文檔清晰簡約。
看看它的主要功能:
MVVM多用于web單頁應用,而小程序明顯不是單頁應用,而且也不支持雙數據綁定,轉為MVVM方式更多只是習慣上的喜好,談不上什么優點。
小程序也支持ES6特性(以前也支持ES7,不知道為什么新版本取消了),用ES6特性可以完成外部NPM包引用。
所以最吸引人的功能就是第二點:支持組件化。
拿到官方給的示例wepy-wechat-demo編譯后對比源碼和編譯后的代碼來探究其實現組件化的思路。
整個項目非常清晰簡單,我們以index頁面調用tab組件為例進行分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// src目錄 - |- components - tab.wpy ... |- pages - index.wpy ... // dist目錄 - dist |- components - tab.wxss - tab.js |- pages - index.js - index.json - index.wxml - index.wxss |
js文件用ES6編寫,通過babel轉成ES5形式,看起來比較費勁,不過幸好我們暫時也不需要分析它。打開index.wxss和tab.wxss可以看到組件樣式的編寫和引用方式如我們所料,通過微信的@import方式引入。
1 2 3 4 5 6 7 8 9 10 11 12 |
// dist/components/tab.wxss .tab { ... } .tab .item { ... } ... // dist/pages/index.wxss @import "./../components/tab.wxss"; ... |
很奇怪,在編譯好的components文件夾中只能看到組件命名的js和wxss文件,wxml文件消失了~
所以先來看看index.wxml中怎么體現的
這段編譯后的代碼和tab.wxml源文件基本一致,發生改變的是數據綁定和事件綁定的地方,進行了重命名。
由此可以推斷,是通過wepy的編譯工具wepy-cli,把頁面上的組件引用替換成了源碼并通過修改變命名來隔離組件作用域避免沖突。
而這些重新修改的變量和事件如何起作用?
wepy的文檔中提到組件支持回調和事件冒泡、事件下發,要支持這個特性除了按其要求的格式進行編寫之外,還需要在js中引用一個叫wepy的模塊,如
import wepy from 'wepy'
由此可以推斷,wepy-cli編譯的時候進行了模板替換和變量名(事件名)替換,然后wepy模塊來處理替換后的事件調用以及組件之間的通信。
如果仔細翻閱文檔會發現其對組件的支持非常接近Vue.js 2.x,比如computed、watcher屬性。行文此處,給作者由衷地點個贊。
那么這種方式是否就是最理想的組件化方式,或者說這種方式有什么缺陷呢?