摘要:在編寫跨端組件的正確姿勢上篇中,我們介紹了如何使用第三方庫封裝跨端組件,但是絕大多數(shù)組件并不需要那樣差異化實(shí)現(xiàn),絕大多數(shù)情況下我們推薦使用語法統(tǒng)一實(shí)現(xiàn)跨端組件。
在chameleon項(xiàng)目中我們實(shí)現(xiàn)一個(gè)跨端組件一般有兩種思路:使用第三方組件封裝與基于chameleon語法統(tǒng)一實(shí)現(xiàn)。
在《編寫chameleon跨端組件的正確姿勢(上篇)》中, 我們介紹了如何使用第三方庫封裝跨端組件,但是絕大多數(shù)組件并不需要那樣差異化實(shí)現(xiàn),絕大多數(shù)情況下我們推薦使用chameleon語法統(tǒng)一實(shí)現(xiàn)跨端組件。本篇是編寫chameleon跨端組件的正確姿勢系列文章的下篇,與上篇給出的示例相同,本篇也以封裝一個(gè)跨端的indexlist組件為例,首先介紹如何使用chameleon語法統(tǒng)一實(shí)現(xiàn)一個(gè)跨端組件,然后對比兩種組件開發(fā)方式并給出開發(fā)建議。
以下效果依此為weex端、web端、支付寶小程序端、微信小程序端以及百度小程序端:
創(chuàng)建一個(gè)新項(xiàng)目 cml-demo
cml init project
進(jìn)入項(xiàng)目
cd cml-demo組件創(chuàng)建
cml init component
選擇“普通組件”, 并并輸入組件名字“indexlist”, 完成組件的創(chuàng)建, 創(chuàng)建之后的組件位于src/components/indexlist文件夾下。
組件設(shè)計(jì)為了方便說明,本例暫時(shí)實(shí)現(xiàn)一個(gè)具備基礎(chǔ)功能的indexlist組件。從功能方面講,indexlist組件主要由兩部分組成,主列表區(qū)域和索引區(qū)域。在用戶點(diǎn)擊組件右側(cè)索引時(shí),主列表能夠快速定位到對應(yīng)區(qū)域;在用戶滑動(dòng)組件主列表時(shí),右側(cè)索引跟隨滑動(dòng)不停切換當(dāng)前索引項(xiàng)。從輸入輸出方面講,組件至少應(yīng)該在用戶選擇某一項(xiàng)時(shí)拋出一個(gè)onselect事件,傳遞用戶當(dāng)前所選中項(xiàng)的數(shù)據(jù);至少應(yīng)該接受一個(gè)datalist,作為其渲染的數(shù)據(jù)源,這個(gè)datalist應(yīng)該是一個(gè)類似于以下結(jié)構(gòu)的對象數(shù)組:
const dataList = [ { name: "阿里", pinYin: "ali", }, { name: "北京", pinYin: "beijing", }, ..... ]主要數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)
根據(jù)設(shè)計(jì)的組件功能與輸入輸出, 我們開始設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)。
indexlist組件右側(cè)的索引列對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為一個(gè)數(shù)組,其中的每一項(xiàng)表示一個(gè)索引,具體結(jié)構(gòu)如下:
this.shortcut = [ "A", "B", "C", ....]
indexlist組件的主列表區(qū)域?qū)?yīng)的數(shù)據(jù)結(jié)構(gòu)也是一個(gè)數(shù)組,其中的每一項(xiàng)表示一個(gè)子列表區(qū)域(例如以首字母a開頭的子列表)。下面我們考慮每一個(gè)子列表區(qū)域中至少應(yīng)該包含的字段:
一個(gè)name字段,表示該子列表區(qū)域的名稱;
一個(gè)items字段,該字段也是一個(gè)數(shù)組,數(shù)組中的每一項(xiàng)表示該子列表區(qū)域的每一項(xiàng);
一個(gè)offsetTop, 表示該子列表區(qū)域距離主列表頂部的距離,通過該字段實(shí)現(xiàn)點(diǎn)擊右側(cè)索引時(shí)能夠通過滾動(dòng)相應(yīng)距離快速定位到該子列表;
一個(gè)totalHeight字段,表示該子列表區(qū)域的所占的高度,通過該字段與offsetTop字段可以確定每個(gè)子列表所在的高度范圍, 以此實(shí)現(xiàn)右側(cè)索引跟隨滑動(dòng)不停切換當(dāng)前索引項(xiàng)
由上面分析可得主列表區(qū)域數(shù)據(jù)結(jié)構(gòu)如下:
this.list = [ { name: "B", items:[ { name: "北京", pinYin: "beijing" }, { name: "包頭", pinYin: "baotou" } ... ], offsetTop: 190, totalHeight: 490 }, .... ]功能實(shí)現(xiàn)
從前文可知,輸入組件的datalist具有如下結(jié)構(gòu):
const dataList = [ { name: "阿里", pinYin: "ali", }, { name: "北京", pinYin: "beijing", }, ..... ]
可以發(fā)現(xiàn)該datalist結(jié)構(gòu)是扁平并且缺乏很多信息(例如totalHeight等)的,因此首先要從輸入數(shù)據(jù)中整理出來所需的數(shù)據(jù)結(jié)構(gòu),修改src/components/indexlist/indexlist.cml的js部分:
initData() { // get shortcut this.dataList.forEach(item => { if (item.pinYin) { let firstName = item.pinYin.substring(0, 1); if (item.pinYin && this.shortcut.indexOf(firstName.toUpperCase()) === -1) { this.shortcut.push(firstName.toUpperCase()); }; }; }); // handle input data const cityData = this.shortcut.map(item => ({items:[], name: item})); this.dataList.forEach((item) => { let firstName = item.pinYin.substring(0, 1).toUpperCase(); let index = this.shortcut.indexOf(firstName); cityData[index].items.push(item); }); // calculate item offsetTop && totalHeight cityData.forEach((item, index) => { let arr = cityData.slice(0, index); item.totalHeight = this.itemNameHeight + item.items.length * this.itemContentHeight; item.offsetTop = arr.reduce((total, cur) => (total + this.itemNameHeight + cur.items.length * this.itemContentHeight), 0); }); this.list = cityData; },
這樣我們就拿到了主列表數(shù)組this.list與索引列表數(shù)組this.shortcut, 然后根據(jù)數(shù)組結(jié)構(gòu)編寫模板內(nèi)容。模板內(nèi)容分為兩大部分,一個(gè)是主列表區(qū)域,修改src/components/indexlist/indexlist.cml文件模板部分:
{{listitem.name}} {{subitem.name}}
其中scroller是一個(gè)chameleon提供的內(nèi)置滾動(dòng)組件,其屬性值scrolltop表示當(dāng)前滾動(dòng)的距離,onscroll表示滾動(dòng)時(shí)觸發(fā)的事件。在主列表這一部分,我們要實(shí)現(xiàn)如下功能:
在滾動(dòng)時(shí),右側(cè)索引不停切換當(dāng)前索引項(xiàng)的功能
點(diǎn)擊列表中的每一項(xiàng)時(shí),向外拋出onselect事件
修改src/components/indexlist/indexlist.cml文件js部分:
handleScroll(e) { let { scrollTop } = e.detail; scrollTop = Math.ceil(scrollTop); this.activeIndex = this.list.findIndex(item => scrollTop >= item.offsetTop && scrollTop < item.totalHeight + item.offsetTop ) }, handleSelect(e) { this.$cmlEmit("onselect", e) }
當(dāng)前激活的索引(this.activeIndex)經(jīng)過計(jì)算得到,規(guī)則為:如果當(dāng)前scroller滾動(dòng)的距離在對應(yīng)子列表所在的高度范圍內(nèi),則認(rèn)為該索引是激活的。
另一部分是索引區(qū)域,修改src/components/indexlist/indexlist.cml文件模板部分,增加索引區(qū)域模板內(nèi)容:
{{item}}
在索引區(qū)域,我們要實(shí)現(xiàn)點(diǎn)擊索引值主列表能夠快速定位到對應(yīng)區(qū)域,修改src/components/indexlist/indexlist.cml文件js部分:
scrollToItem(shortcut) { let { offsetTop } = this.list.find(item => item.name === shortcut); this.offsetTop = offsetTop; }
索引區(qū)域應(yīng)該定位在視窗右側(cè)并且上下居中。由于chameleon暫時(shí)不支持在css中使用百分比,因此我們通過chameleon-api提供的對外接口獲取屏幕視窗高度,然后使用js計(jì)算得到位置, 配合部分css來實(shí)現(xiàn)索引區(qū)域定位在視窗右側(cè)居中。修改src/components/indexlist/indexlist.cml文件js部分:
// computed compScwStyle() { return `top:${this.viewportHeight / 2}cpx` } // method async getViewportHeight() { let res = await cml.getSystemInfo(); this.viewportHeight = res.viewportHeight; },
至此便通過chameleon語法統(tǒng)一實(shí)現(xiàn)了一個(gè)跨端indexlist組件,該組件直接可以在web、weex、微信小程序、支付寶小程序與百度小程序五個(gè)端運(yùn)行。為了方便描述,上述代碼只是簡單介紹了組件實(shí)現(xiàn)的核心代碼,跳過了樣式和一些邏輯細(xì)節(jié)。
修改src/pages/index/index.cml文件里面的json配置,引用創(chuàng)建的indexlist組件
"base": { "usingComponents": { "indexlist": "/components/indexlist/indexlist" } },
修改src/pages/index/index.cml文件中的模板部分,引用創(chuàng)建的indexlist組件
其中dataList是一個(gè)對象數(shù)組,表示組件要渲染的數(shù)據(jù)源
一些思考本篇文章主要介紹了如何通過chameleon語法實(shí)現(xiàn)跨端組件。對比編寫chameleon跨端組件的正確姿勢(上篇).md)介紹的通過第三方庫封裝的方法可以發(fā)現(xiàn),兩種方式是完全不同的,現(xiàn)詳細(xì)對比一下這兩種實(shí)現(xiàn)方式的優(yōu)勢與劣勢, 并給出開發(fā)建議:
優(yōu)勢 | 劣勢 | 開發(fā)建議 | |
基于第三方組件庫實(shí)現(xiàn) | - 可利用已有生態(tài)迅速完成跨端組件 |
- 組件的實(shí)現(xiàn)依賴第三方庫,如果沒有成熟的對應(yīng)端第三方庫則無法完成該端組件開發(fā) - 由于各端第三方組件存在差異,封裝的跨端組件樣式與功能存在差異 - 第三方組件升級時(shí),要對應(yīng)調(diào)整跨端組件的實(shí)現(xiàn),維護(hù)成本較大 - 第三方組件庫質(zhì)量不能得到保證 |
- 將基于各端第三方組件封裝跨端組件庫的方法作為臨時(shí)方案
- 對于特別復(fù)雜并且已有成熟第三方庫或者框架能力暫時(shí)不支持的組件,可以考慮使用第三方組件封裝成對應(yīng)的跨端組件,例如圖表組件、地圖組件等等 |
基于chameleon統(tǒng)一實(shí)現(xiàn) |
- 新的端接入時(shí),能夠直接運(yùn)行 - 一般情況下,不存在各端樣式與功能差異 - 絕大部分組件不需要各端差異化實(shí)現(xiàn),使用chameleon語法實(shí)現(xiàn)開發(fā)與維護(hù)成本更低 - 能夠?qū)С鲈M件供多端使用 |
- 從零搭建時(shí)間與技術(shù)成本較高 |
從長期維護(hù)的角度來講,建議使用chameleon生態(tài)來統(tǒng)一實(shí)現(xiàn)跨端組件庫 如果僅僅是各端api層面的不同,建議使用多態(tài)接口抹平差異,而不使用多態(tài)組件 |
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102464.html
摘要:使用語法統(tǒng)一實(shí)現(xiàn)跨端組件請關(guān)注文章編寫跨端組件的正確姿勢下篇依靠強(qiáng)大的多態(tài)協(xié)議,項(xiàng)目中可以輕松使用各端的第三方組件封裝自己的跨端組件庫。這種做法同時(shí)解決了組件命名沖突問題,例如在微信小程序端引用表示調(diào)用小程序原生的組件而不是內(nèi)置的組件。 在chameleon項(xiàng)目中我們實(shí)現(xiàn)一個(gè)跨端組件一般有兩種思路:使用第三方組件封裝與基于chameleon語法統(tǒng)一實(shí)現(xiàn)。本篇是編寫chameleon跨端...
摘要:基于對跨端工作的積累,規(guī)范了一套跨端標(biāo)準(zhǔn),稱之為協(xié)議開發(fā)者只需要按照標(biāo)準(zhǔn)擴(kuò)展流程,即可快速擴(kuò)展任意架構(gòu)模式的終端。實(shí)現(xiàn)了微信端的基本擴(kuò)展,用戶可以以此為模板進(jìn)行開發(fā)。新框架太多?學(xué)不動(dòng)啦?有這一套跨端標(biāo)準(zhǔn),今后再也不用學(xué)習(xí)新框架了。各個(gè)小程序按自己喜好各自為政?有了這套標(biāo)準(zhǔn),再也不用重復(fù)開發(fā)各種新平臺啦。如今前端比較流行的 React Native、Weex、Flutter 等跨平臺開發(fā)框架...
摘要:但是從年微信推出小程序,到至今各大廠商都推出自己的小程序,跨端開發(fā)就不僅僅是技術(shù)的問題了。實(shí)現(xiàn)了微信端的基本擴(kuò)展,用戶可以以此為模板進(jìn)行開發(fā)。 新框架太多?學(xué)不動(dòng)啦?有這一套跨端標(biāo)準(zhǔn),今后再也不用學(xué)習(xí)新框架了。 各個(gè)小程序按自己喜好各自為政?有了這套標(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)計(jì)報(bào)告顯示,截至年月,我國網(wǎng)民規(guī)模達(dá)億人,微信月活億支付寶月活億百度月活億另一方面,中國手機(jī)占智能手機(jī)整體的比例超過,月活約億。在年末正式發(fā)布了面向未來的跨端的。 開源中國專訪:Chameleon原理首發(fā),其它跨多端統(tǒng)一框架都是假的? 原創(chuàng): 嘉賓-張楠 開源中國 以往我們說某一功能跨多端,往往是指在諸如 PC、移動(dòng)等不同類型的設(shè)備之...
閱讀 3633·2023-04-25 23:32
閱讀 2048·2019-08-30 15:55
閱讀 2661·2019-08-30 15:52
閱讀 3120·2019-08-30 10:54
閱讀 848·2019-08-29 16:16
閱讀 657·2019-08-29 15:09
閱讀 3661·2019-08-26 14:05
閱讀 1642·2019-08-26 13:22