摘要:使用語法統(tǒng)一實現(xiàn)跨端組件請關(guān)注文章編寫跨端組件的正確姿勢下篇依靠強(qiáng)大的多態(tài)協(xié)議,項目中可以輕松使用各端的第三方組件封裝自己的跨端組件庫。這種做法同時解決了組件命名沖突問題,例如在微信小程序端引用表示調(diào)用小程序原生的組件而不是內(nèi)置的組件。
在chameleon項目中我們實現(xiàn)一個跨端組件一般有兩種思路:使用第三方組件封裝與基于chameleon語法統(tǒng)一實現(xiàn)。本篇是編寫chameleon跨端組件的正確姿勢系列文章的上篇,以封裝一個跨端的indexlist組件為例,首先介紹如何優(yōu)雅的使用第三方庫封裝跨端組件,然后給出編寫chameleon跨端組件的建議。使用chameleon語法統(tǒng)一實現(xiàn)跨端組件請關(guān)注文章《編寫chameleon跨端組件的正確姿勢(下篇)》
依靠強(qiáng)大的多態(tài)協(xié)議,chameleon項目中可以輕松使用各端的第三方組件封裝自己的跨端組件庫。基于第三方組件可以利用現(xiàn)有生態(tài)迅速實現(xiàn)需求,但是卻存在很多缺點(diǎn),例如多端第三方組件本身的功能與樣式差異、組件質(zhì)量得不到保證以及絕大部分組件并不需要通過多態(tài)組件差異化實現(xiàn),這樣反而提升了長期的維護(hù)成本;使用chameleon語法統(tǒng)一實現(xiàn)則可以完美解決上述問題,并且擴(kuò)展一個新的端時現(xiàn)有組件可以直接運(yùn)行。本文的最后也會詳細(xì)對比一下兩種方案的優(yōu)劣。
因此,建議將通過第三方庫實現(xiàn)跨端組件庫作為臨時方案,從長期維護(hù)的角度來講,建議開發(fā)者使用chameleon語法統(tǒng)一實現(xiàn)絕大部分跨端組件,只有一些特別復(fù)雜并且已有成熟第三方庫或者框架能力暫時不支持的組件,才考慮使用第三方組件封裝成對應(yīng)的跨端組件。
由于本文介紹的是使用第三方庫封裝跨端組件, 因此示例的indexlist組件采用第三方組件封裝來實現(xiàn), 通過chameleon統(tǒng)一實現(xiàn)跨端組件的方法可以看《編寫chameleon跨端組件的正確姿勢(下篇)》。
最終實現(xiàn)的indexlist效果圖:
前期準(zhǔn)備使用各端第三方組件實現(xiàn)chameleon跨端組件需要如下前期準(zhǔn)備:
創(chuàng)建一個新項目 cml-demo
cml init project
進(jìn)入項目
cd cml-demo
開發(fā)一個模塊時我們首先應(yīng)該根據(jù)功能確定其輸入與輸出,對應(yīng)到組件開發(fā)上來說,就是要確定組件的屬性和事件,其中屬性表示組件接受的輸入,而事件則表示組件在特定時機(jī)對外的輸出。
為了方便說明,本例暫時實現(xiàn)一個具備基礎(chǔ)功能的indexlist。一個indexlist組件至少應(yīng)該在用戶選擇某一項時拋出一個onselect事件,傳遞用戶當(dāng)前所選中項的數(shù)據(jù);至少應(yīng)該接受一個datalist,作為其渲染的數(shù)據(jù)源,這個datalist應(yīng)該是一個類似于以下結(jié)構(gòu)的對象數(shù)組:
const dataList = [ { name: "阿里", pinYin: "ali", py: "al" }, { name: "北京", pinYin: "beijing", py: "bj" }, ..... ]
由于本文介紹的是如何使用第三方庫封裝跨端組件,因此在確定組件需求以及實現(xiàn)思路后去尋找符合要求的第三方庫。在開發(fā)之前,作者調(diào)研了目前較為流行的各端組件庫,推薦如下:
web端:
cube-ui
vux
mint-ui
vant
wx端:
iview weapp
vant weapp
weui
weex端:
weex-ui
除了上述組件庫之外,開發(fā)者也可以根據(jù)自己的實際需求去尋找經(jīng)過包裝之后符合預(yù)期的第三方庫。截止文章編寫時,作者未找到較成熟的支付寶及百度小程序第三方庫,因此暫時先實現(xiàn)web、微信小程序以及weex端,這也體現(xiàn)出了使用第三方庫擴(kuò)展跨端組件的局限性:當(dāng)沒有成熟的對應(yīng)端第三方庫時,無法完成該端的組件開發(fā);而使用chameleon語法統(tǒng)一實現(xiàn)則可以解決上述問題,擴(kuò)展新的端時已有組件能夠直接運(yùn)行,無需額外擴(kuò)展。 本文在實現(xiàn)indexlist組件時分別使用了cube-ui, iview weapp以及weex-ui, 以下會介紹具體的開發(fā)過程.
組件開發(fā)創(chuàng)建多態(tài)組件
cml init component
選擇“多態(tài)組件”, 并輸入組件名字“indexlist”, 完成組件的創(chuàng)建, 創(chuàng)建之后的組件位于src/components/indexlist文件夾下。
多態(tài)組件中的.interface文件利用接口校驗語法對組件的屬性和事件進(jìn)行類型定義,保證各端的屬性和事件一致。確定了組件的屬性與事件之后就開始編寫.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代碼, 根據(jù)cube-ui文檔將數(shù)據(jù)處理成符合其組件預(yù)期的結(jié)構(gòu), 并向上拋出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組件的開發(fā),效果如下:
安裝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();
編寫必要樣式,此時發(fā)現(xiàn)weex端與web端有部分重復(fù)樣式,因此將樣式抽離出來創(chuàng)建indexlist.less,在web端與weex端的cml文件中引入該樣式
indexlist.less文件內(nèi)容:
.index-list-wrapper { width: 750cpx; height: 1200cpx; }
以上便使用weex-ui完成了weex端indexlist組件的開發(fā),效果如下:
根據(jù)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代碼, 根據(jù)iview weapp文檔將數(shù)據(jù)處理成符合其組件預(yù)期的結(jié)構(gòu), 并向上拋出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組件的開發(fā), 效果如下:
修改src/pages/index/index.cml文件里面的json配置,引用創(chuàng)建的indexlist組件
"base": { "usingComponents": { "indexlist": "/components/indexlist/indexlist" } },
修改src/pages/index/index.cml文件中的模板部分,引用創(chuàng)建的indexlist組件
其中dataList是一個對象數(shù)組,表示組件要渲染的數(shù)據(jù)源。具體結(jié)構(gòu)為:
const dataList = [ { name: "阿里", pinYin: "ali", py: "al" }, { name: "北京", pinYin: "beijing", py: "bj" }, ..... ]
根據(jù)上述例子可以看出,chameleon項目可以輕松結(jié)合第三方庫封裝自己的跨端組件庫。使用第三方組件封裝跨端組件庫的步驟大致如下:
跨端組件設(shè)計
根據(jù)實際需求引入合適的第三方組件
根據(jù)第三方組件文檔,將數(shù)據(jù)處理成符合預(yù)期的結(jié)構(gòu),并在適當(dāng)時機(jī)拋出事件
編寫必要樣式
一些思考根據(jù)組件多態(tài)文檔, 像indexlist.web.cml、indexlist.wx.cml與indexlist.weex.cml的這些文件是灰度區(qū), 它們是唯一可以調(diào)用下層端能力的CML文件,這里的下層端能力既包含下層端組件,例如在web端和weex端的.vue文件等;也包含下層端的api,例如微信小程序的wx.pageScrollTo等。這一層的存在是為了調(diào)用下層端代碼,各端具體的邏輯實現(xiàn)應(yīng)該在下層來實現(xiàn), 這種規(guī)范的好處是顯而易見的: 隨著業(yè)務(wù)復(fù)雜度的提升,各個下層端維護(hù)的功能逐漸變多,其中通用的部分又可以通過普通cml文件抽離出來被統(tǒng)一調(diào)用,這樣可以保證差異化部分始終是最小集合,灰度區(qū)是存粹的;如果將業(yè)務(wù)邏輯都放在了灰度區(qū),隨著功能復(fù)雜度的上升,三端通用功能/組件就無法達(dá)到合理的抽象,導(dǎo)致灰度層既有相同功能,又有差異化部分,這顯然不是開發(fā)者愿意看到的場景。
在灰度區(qū)的模板、邏輯、樣式和json文件中分別具有如下規(guī)則:
模板
調(diào)用下層組件時,既可以使用chameleon語法,也可以使用各端原生語法;在灰度區(qū)chameleon編譯器不會編譯各個端原生語法,例如v-for,bindtap等。建議在模板部分仍然使用chameleon模板語法,只有在實現(xiàn)對應(yīng)平臺不支持的語法(例如web端v-html等)時才使用原生語法。
引用下層全局組件時需要添加origin-前綴,這樣可以“告訴”chameleon編譯器是在引用下層的原生組件,chameleon編譯器就不會對其進(jìn)行處理了。這種做法同時解決了組件命名沖突問題,例如在微信小程序端引用
邏輯
在script邏輯代碼中,除了編寫普通cml邏輯代碼之外,開發(fā)者還可以使用下層端的全局變量和任意方法,包括生命周期函數(shù)。這種機(jī)制保證開發(fā)者可以靈活擴(kuò)展各端特有功能,而不需要依賴多態(tài)接口。
樣式
既可以使用cmss語法也可以使用下層端的css語法。
json文件
*web.cml:base.usingComponents可以引入普通cml組件和任意.vue擴(kuò)展名組件,路徑規(guī)則見組件配置。
*wx.cml:base.usingComponents可以引入普通cml組件和普通微信小程序組件,路徑規(guī)則見組件配置。
*weex.cml:base.usingComponents可以引入普通cml組件和任意.vue擴(kuò)展名組件,路徑規(guī)則見組件配置。
在各端對應(yīng)的灰度區(qū)文件中均可以根據(jù)上述規(guī)范使用各端的原生語法,但是為了規(guī)范仍然建議使用chameleon體系的語法規(guī)則。總體來說,灰度區(qū)可以認(rèn)為是chameleon體系與各端原生組件/方法的銜接點(diǎn),向下使用各端功能/組件,向上通過多態(tài)協(xié)議提供各端統(tǒng)一的調(diào)用接口。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102465.html
摘要:在編寫跨端組件的正確姿勢上篇中,我們介紹了如何使用第三方庫封裝跨端組件,但是絕大多數(shù)組件并不需要那樣差異化實現(xiàn),絕大多數(shù)情況下我們推薦使用語法統(tǒng)一實現(xiàn)跨端組件。 在chameleon項目中我們實現(xiàn)一個跨端組件一般有兩種思路:使用第三方組件封裝與基于chameleon語法統(tǒng)一實現(xiàn)。在《編寫chameleon跨端組件的正確姿勢(上篇)》中, 我們介紹了如何使用第三方庫封裝跨端組件,但是絕大...
摘要:基于對跨端工作的積累,規(guī)范了一套跨端標(biāo)準(zhǔn),稱之為協(xié)議開發(fā)者只需要按照標(biāo)準(zhǔn)擴(kuò)展流程,即可快速擴(kuò)展任意架構(gòu)模式的終端。實現(xiàn)了微信端的基本擴(kuò)展,用戶可以以此為模板進(jìn)行開發(fā)。新框架太多?學(xué)不動啦?有這一套跨端標(biāo)準(zhǔn),今后再也不用學(xué)習(xí)新框架了。各個小程序按自己喜好各自為政?有了這套標(biāo)準(zhǔn),再也不用重復(fù)開發(fā)各種新平臺啦。如今前端比較流行的 React Native、Weex、Flutter 等跨平臺開發(fā)框架...
摘要:但是從年微信推出小程序,到至今各大廠商都推出自己的小程序,跨端開發(fā)就不僅僅是技術(shù)的問題了。實現(xiàn)了微信端的基本擴(kuò)展,用戶可以以此為模板進(jìn)行開發(fā)。 新框架太多?學(xué)不動啦?有這一套跨端標(biāo)準(zhǔn),今后再也不用學(xué)習(xí)新框架了。 各個小程序按自己喜好各自為政?有了這套標(biāo)準(zhǔn),再也不用重復(fù)開發(fā)各種新平臺啦。 如今前端比較流行的 React Native、Weex、Flutter 等跨平臺開發(fā)框架,對于開發(fā)來...
摘要:中國互聯(lián)網(wǎng)絡(luò)信息中心發(fā)布的中國互聯(lián)網(wǎng)絡(luò)發(fā)展?fàn)顩r統(tǒng)計報告顯示,截至年月,我國網(wǎng)民規(guī)模達(dá)億人,微信月活億支付寶月活億百度月活億另一方面,中國手機(jī)占智能手機(jī)整體的比例超過,月活約億。在年末正式發(fā)布了面向未來的跨端的。 開源中國專訪:Chameleon原理首發(fā),其它跨多端統(tǒng)一框架都是假的? 原創(chuàng): 嘉賓-張楠 開源中國 以往我們說某一功能跨多端,往往是指在諸如 PC、移動等不同類型的設(shè)備之...
閱讀 2573·2023-04-26 02:47
閱讀 3035·2023-04-26 00:42
閱讀 899·2021-10-12 10:12
閱讀 1422·2021-09-29 09:35
閱讀 1727·2021-09-26 09:55
閱讀 511·2019-08-30 14:00
閱讀 1566·2019-08-29 12:57
閱讀 2385·2019-08-28 18:00