摘要:使用語法統一實現跨端組件請關注文章編寫跨端組件的正確姿勢下篇依靠強大的多態協議,項目中可以輕松使用各端的第三方組件封裝自己的跨端組件庫。這種做法同時解決了組件命名沖突問題,例如在微信小程序端引用表示調用小程序原生的組件而不是內置的組件。
在chameleon項目中我們實現一個跨端組件一般有兩種思路:使用第三方組件封裝與基于chameleon語法統一實現。本篇是編寫chameleon跨端組件的正確姿勢系列文章的上篇,以封裝一個跨端的indexlist組件為例,首先介紹如何優雅的使用第三方庫封裝跨端組件,然后給出編寫chameleon跨端組件的建議。使用chameleon語法統一實現跨端組件請關注文章《編寫chameleon跨端組件的正確姿勢(下篇)》
依靠強大的多態協議,chameleon項目中可以輕松使用各端的第三方組件封裝自己的跨端組件庫。基于第三方組件可以利用現有生態迅速實現需求,但是卻存在很多缺點,例如多端第三方組件本身的功能與樣式差異、組件質量得不到保證以及絕大部分組件并不需要通過多態組件差異化實現,這樣反而提升了長期的維護成本;使用chameleon語法統一實現則可以完美解決上述問題,并且擴展一個新的端時現有組件可以直接運行。本文的最后也會詳細對比一下兩種方案的優劣。
因此,建議將通過第三方庫實現跨端組件庫作為臨時方案,從長期維護的角度來講,建議開發者使用chameleon語法統一實現絕大部分跨端組件,只有一些特別復雜并且已有成熟第三方庫或者框架能力暫時不支持的組件,才考慮使用第三方組件封裝成對應的跨端組件。
由于本文介紹的是使用第三方庫封裝跨端組件, 因此示例的indexlist組件采用第三方組件封裝來實現, 通過chameleon統一實現跨端組件的方法可以看《編寫chameleon跨端組件的正確姿勢(下篇)》。
最終實現的indexlist效果圖:
前期準備使用各端第三方組件實現chameleon跨端組件需要如下前期準備:
創建一個新項目 cml-demo
cml init project
進入項目
cd cml-demo
開發一個模塊時我們首先應該根據功能確定其輸入與輸出,對應到組件開發上來說,就是要確定組件的屬性和事件,其中屬性表示組件接受的輸入,而事件則表示組件在特定時機對外的輸出。
為了方便說明,本例暫時實現一個具備基礎功能的indexlist。一個indexlist組件至少應該在用戶選擇某一項時拋出一個onselect事件,傳遞用戶當前所選中項的數據;至少應該接受一個datalist,作為其渲染的數據源,這個datalist應該是一個類似于以下結構的對象數組:
const dataList = [ { name: "阿里", pinYin: "ali", py: "al" }, { name: "北京", pinYin: "beijing", py: "bj" }, ..... ]
由于本文介紹的是如何使用第三方庫封裝跨端組件,因此在確定組件需求以及實現思路后去尋找符合要求的第三方庫。在開發之前,作者調研了目前較為流行的各端組件庫,推薦如下:
web端:
cube-ui
vux
mint-ui
vant
wx端:
iview weapp
vant weapp
weui
weex端:
weex-ui
除了上述組件庫之外,開發者也可以根據自己的實際需求去尋找經過包裝之后符合預期的第三方庫。截止文章編寫時,作者未找到較成熟的支付寶及百度小程序第三方庫,因此暫時先實現web、微信小程序以及weex端,這也體現出了使用第三方庫擴展跨端組件的局限性:當沒有成熟的對應端第三方庫時,無法完成該端的組件開發;而使用chameleon語法統一實現則可以解決上述問題,擴展新的端時已有組件能夠直接運行,無需額外擴展。 本文在實現indexlist組件時分別使用了cube-ui, iview weapp以及weex-ui, 以下會介紹具體的開發過程.
組件開發創建多態組件
cml init component
選擇“多態組件”, 并輸入組件名字“indexlist”, 完成組件的創建, 創建之后的組件位于src/components/indexlist文件夾下。
多態組件中的.interface文件利用接口校驗語法對組件的屬性和事件進行類型定義,保證各端的屬性和事件一致。確定了組件的屬性與事件之后就開始編寫.interface文件, 修改src/components/indexlist/indexlist.interface:
type eventDetail = { name: String, pinYin: String, py: String } type arrayItem = { name: String, pinYin: String, py: String } type arr = [arrayItem]; interface IndexlistInterface { dataList: arr, onselect(eventDetail: eventDetail): void }
具體的interface文件語法可以參考此處, 本文不再贅述。
安裝cube-ui
npm i cube-ui -S
在src/components/indexlist/indexlist.web.cml的json文件中引入cube-ui的indexlist組件
"base": { "usingComponents": { "cube-index-list": "cube-ui/src/components/index-list/index-list" } }
修改src/components/indexlist/indexlist.web.cml中的模板代碼,引用cube-ui的indexlist組件:
修改src/components/indexlist/indexlist.web.cml中的js代碼, 根據cube-ui文檔將數據處理成符合其組件預期的結構, 并向上拋出onselect事件:
const words = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]; class Indexlist implements IndexlistInterface { props = { dataList: { type: Array, default() { return [] } } } data = { list: [], } methods = { initData() { const cityData = []; words.forEach((item, index) => { cityData[index] = {}; cityData[index].items = []; cityData[index].name = item; }); this.dataList.forEach((item) => { let firstName = item.pinYin.substring(0, 1).toUpperCase(); let index = words.indexOf(firstName); cityData[index].items.push(item) }); this.list = cityData; }, onItemSelect(item) { this.$cmlEmit("onselect", item); } } mounted() { this.initData(); } } export default new Indexlist();
編寫必要的樣式:
.index-list-wrapper { width: 750cpx; height: 1200cpx; }
以上便使用cube-ui完成了web端indexlist組件的開發,效果如下:
安裝weex-ui
npm i weex-ui -S
在src/components/indexlist/indexlist.weex.cml的json文件中引入weex-ui的wxc-indexlist組件:
"base": { "usingComponents": { "wex-indexlist": "weex-ui/packages/wxc-indexlist" } }
修改src/components/indexlist/indexlist.weex.cml中的模板代碼,引用weex-ui的wxc-indexlist組件:
修改src/components/indexlist/indexlist.weex.cml中的js代碼:
class Indexlist implements IndexlistInterface { props = { dataList: { type: Array, default() { return [] } } } data = { list: [], } mounted() { this.initData(); } methods = { initData() { this.list = this.dataList; }, onItemSelect(e) { this.$cmlEmit("onselect", e.item); } } } export default new Indexlist();
編寫必要樣式,此時發現weex端與web端有部分重復樣式,因此將樣式抽離出來創建indexlist.less,在web端與weex端的cml文件中引入該樣式
indexlist.less文件內容:
.index-list-wrapper { width: 750cpx; height: 1200cpx; }
以上便使用weex-ui完成了weex端indexlist組件的開發,效果如下:
根據iview weapp文檔, 首先到Github下載iview weapp代碼,將dist目錄拷貝到項目的src目錄下,然后在src/components/indexlist/indexlist.wx.cml的json文件中引入iview的index與index-item組件:
"base": { "usingComponents": { "i-index":"/iview/index/index", "i-index-item": "/iview/index-item/index" } },
修改src/components/indexlist/indexlist.wx.cml中的模板代碼,引用iview的index與index-item組件:
{{it.name}}
修改src/components/indexlist/indexlist.wx.cml中的js代碼, 根據iview weapp文檔將數據處理成符合其組件預期的結構, 并向上拋出onselect事件:
const words = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]; class Indexlist implements IndexlistInterface { props = { dataList: { type: Array, default() { return [] } } } data = { cities: [] } methods = { initData() { let storeCity = new Array(26); words.forEach((item,index)=>{ storeCity[index] = { key: item, list: [] }; }); this.dataList.forEach((item)=>{ let firstName = item.pinYin.substring(0,1).toUpperCase(); let index = words.indexOf(firstName); storeCity[index].list.push(item); }); this.cities = storeCity; }, onItemSelect(item) { this.$cmlEmit("onselect", item); } } mounted() { this.initData(); } } export default new Indexlist();
編寫必要樣式:
@import "indexlist.less"; .index-list { &-item { height: 90cpx; padding-left: 20cpx; justify-content: center; border-bottom: 1cpx solid #F7F7F7 } }
以上便使用iview weapp完成了wx端indexlist組件的開發, 效果如下:
修改src/pages/index/index.cml文件里面的json配置,引用創建的indexlist組件
"base": { "usingComponents": { "indexlist": "/components/indexlist/indexlist" } },
修改src/pages/index/index.cml文件中的模板部分,引用創建的indexlist組件
其中dataList是一個對象數組,表示組件要渲染的數據源。具體結構為:
const dataList = [ { name: "阿里", pinYin: "ali", py: "al" }, { name: "北京", pinYin: "beijing", py: "bj" }, ..... ]
根據上述例子可以看出,chameleon項目可以輕松結合第三方庫封裝自己的跨端組件庫。使用第三方組件封裝跨端組件庫的步驟大致如下:
跨端組件設計
根據實際需求引入合適的第三方組件
根據第三方組件文檔,將數據處理成符合預期的結構,并在適當時機拋出事件
編寫必要樣式
一些思考根據組件多態文檔, 像indexlist.web.cml、indexlist.wx.cml與indexlist.weex.cml的這些文件是灰度區, 它們是唯一可以調用下層端能力的CML文件,這里的下層端能力既包含下層端組件,例如在web端和weex端的.vue文件等;也包含下層端的api,例如微信小程序的wx.pageScrollTo等。這一層的存在是為了調用下層端代碼,各端具體的邏輯實現應該在下層來實現, 這種規范的好處是顯而易見的: 隨著業務復雜度的提升,各個下層端維護的功能逐漸變多,其中通用的部分又可以通過普通cml文件抽離出來被統一調用,這樣可以保證差異化部分始終是最小集合,灰度區是存粹的;如果將業務邏輯都放在了灰度區,隨著功能復雜度的上升,三端通用功能/組件就無法達到合理的抽象,導致灰度層既有相同功能,又有差異化部分,這顯然不是開發者愿意看到的場景。
在灰度區的模板、邏輯、樣式和json文件中分別具有如下規則:
模板
調用下層組件時,既可以使用chameleon語法,也可以使用各端原生語法;在灰度區chameleon編譯器不會編譯各個端原生語法,例如v-for,bindtap等。建議在模板部分仍然使用chameleon模板語法,只有在實現對應平臺不支持的語法(例如web端v-html等)時才使用原生語法。
引用下層全局組件時需要添加origin-前綴,這樣可以“告訴”chameleon編譯器是在引用下層的原生組件,chameleon編譯器就不會對其進行處理了。這種做法同時解決了組件命名沖突問題,例如在微信小程序端引用
邏輯
在script邏輯代碼中,除了編寫普通cml邏輯代碼之外,開發者還可以使用下層端的全局變量和任意方法,包括生命周期函數。這種機制保證開發者可以靈活擴展各端特有功能,而不需要依賴多態接口。
樣式
既可以使用cmss語法也可以使用下層端的css語法。
json文件
*web.cml:base.usingComponents可以引入普通cml組件和任意.vue擴展名組件,路徑規則見組件配置。
*wx.cml:base.usingComponents可以引入普通cml組件和普通微信小程序組件,路徑規則見組件配置。
*weex.cml:base.usingComponents可以引入普通cml組件和任意.vue擴展名組件,路徑規則見組件配置。
在各端對應的灰度區文件中均可以根據上述規范使用各端的原生語法,但是為了規范仍然建議使用chameleon體系的語法規則。總體來說,灰度區可以認為是chameleon體系與各端原生組件/方法的銜接點,向下使用各端功能/組件,向上通過多態協議提供各端統一的調用接口。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102465.html
摘要:在編寫跨端組件的正確姿勢上篇中,我們介紹了如何使用第三方庫封裝跨端組件,但是絕大多數組件并不需要那樣差異化實現,絕大多數情況下我們推薦使用語法統一實現跨端組件。 在chameleon項目中我們實現一個跨端組件一般有兩種思路:使用第三方組件封裝與基于chameleon語法統一實現。在《編寫chameleon跨端組件的正確姿勢(上篇)》中, 我們介紹了如何使用第三方庫封裝跨端組件,但是絕大...
摘要:基于對跨端工作的積累,規范了一套跨端標準,稱之為協議開發者只需要按照標準擴展流程,即可快速擴展任意架構模式的終端。實現了微信端的基本擴展,用戶可以以此為模板進行開發。新框架太多?學不動啦?有這一套跨端標準,今后再也不用學習新框架了。各個小程序按自己喜好各自為政?有了這套標準,再也不用重復開發各種新平臺啦。如今前端比較流行的 React Native、Weex、Flutter 等跨平臺開發框架...
摘要:但是從年微信推出小程序,到至今各大廠商都推出自己的小程序,跨端開發就不僅僅是技術的問題了。實現了微信端的基本擴展,用戶可以以此為模板進行開發。 新框架太多?學不動啦?有這一套跨端標準,今后再也不用學習新框架了。 各個小程序按自己喜好各自為政?有了這套標準,再也不用重復開發各種新平臺啦。 如今前端比較流行的 React Native、Weex、Flutter 等跨平臺開發框架,對于開發來...
摘要:中國互聯網絡信息中心發布的中國互聯網絡發展狀況統計報告顯示,截至年月,我國網民規模達億人,微信月活億支付寶月活億百度月活億另一方面,中國手機占智能手機整體的比例超過,月活約億。在年末正式發布了面向未來的跨端的。 開源中國專訪:Chameleon原理首發,其它跨多端統一框架都是假的? 原創: 嘉賓-張楠 開源中國 以往我們說某一功能跨多端,往往是指在諸如 PC、移動等不同類型的設備之...
閱讀 2519·2023-04-26 02:47
閱讀 3004·2023-04-26 00:42
閱讀 873·2021-10-12 10:12
閱讀 1381·2021-09-29 09:35
閱讀 1694·2021-09-26 09:55
閱讀 483·2019-08-30 14:00
閱讀 1539·2019-08-29 12:57
閱讀 2358·2019-08-28 18:00