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