在螞蟻金服的開放平臺上看到一些貼子,說提供一個工具,一鍵轉(zhuǎn)換微信小程序為支付寶小程序。我與百度的人交流時,也聽到相似的東西。其實都沒有這么簡單,它們最多是將一些循環(huán)條件分支指令改一下名,將一些文件的后綴名改一下,更多的差異點在API與各式的配置對象上,細節(jié)是魔鬼,我在娜娜奇的官網(wǎng)也列舉了許多相關的東西,但也不能打票說已經(jīng)很齊全。。。。
各種小程序的差異點-文檔
補充一句,娜娜奇是我們公司的小程序開發(fā)框架,以React方式轉(zhuǎn)譯成各種小程序與快應用的框架。類似于京東的taro。
最近忙于支付寶小程序的開發(fā),我得到許多有關小程序的一手資料,包括自己測試得到的,及從百度,小米快應用與支付寶內(nèi)部人士提供的。
本文將重點說一下小程序的組件機制,之前娜娜奇的組件機制是基于template標簽實現(xiàn)的,但百度的template有點BUG,給他們提了,不知現(xiàn)在修了沒有。與template機制在快應用又出入太大,于是轉(zhuǎn)向用自定義組件機制開發(fā)娜娜奇的組件機制。下面鏈接有一些相關的測試與說明
轉(zhuǎn)換小程序 · Issue #133 · RubyLouvre/anu
經(jīng)測試,使用了自定義組件機制的確是比template實現(xiàn)的簡潔一些。但自定義組件機制是一個比較高級的特性,因此兼容性上比template差多了。只能內(nèi)部推到各方改進了。
微信在Component的配置對象提供了一些對象如methods, lifetimes,pageLifetimes,來減少其直轄的配置項。
比如說lifetimes收納了created、attached、ready、moved、detached這些生命周期鉤子,pageLifetimes收納了onShow, onHide這些與頁面切換的鉤子,methods收納剩下的方法,另外還有許多配置項。的確,微信小程序獨自發(fā)布這么久,肯定是最完善的
支付寶的自定義組件機制沒有properties,只有props,并且作用也不一樣,props只是指定默認值,不是規(guī)定參數(shù)類型。支付寶也沒有l(wèi)ifetimes與pageLifetimes對象,生命周期函數(shù)的名字也不一樣 didMount 、didUpdate 、didUnmount,數(shù)量也少了,但從名稱來看,支付寶在內(nèi)部應該運行一個自己的迷你React。
其他方面,支付寶沒有 dataset, selectComponent,selectAllComponents,getRelationNodes這些東西,但支持了早被React廢棄的mixin機制。
支付寶沒有created這樣的鉤子是相當麻煩的事,因此積級推動他們加上這個鉤子!
百度的自定義組件機制與微信的較為相近,但也沒有l(wèi)ifetimes與pageLifetimes對象,只有4種生命周期鉤子:created,attached,ready,detached。有selectComponent,selectAllComponents。
快應用的頁面與組件的配置對象都是一樣,但它沒有構造函數(shù),只是要求我們export一個對象
有props對象,用來定義類型與默認值,也有與state相似的data對象,也有三個做了訪問限制的private, protected, public對象。生命周期鉤子上有onInit、onReady、onDestroy這三個。
從組件的設計來看, 微信 > 百度 > 支付寶 > 快應用
因此想兼容這么多種小程序,我們必須自己寫一個工廠方法,根據(jù)不同的平臺生成不同的配置項,并且放棄掉一些微信的強大功能了。
var hooksName = { wx: ['created', 'attached', 'detached'], bu: ['created', 'attached', 'detached'], ali: ['didMount', 'didMount', 'didUnmount'], quick: ['onInit', 'onReady', 'onDestroy'], }; export function registerComponent(type, name) { registerComponents[name] = type; var reactInstances = (type.reactInstances = []); var wxInstances = (type.wxInstances = []); var hooks = [ function created() { var instance = reactInstances.shift(); if (instance) { console.log('created時為', name, '添加wx'); instance.wx = this; this.reactInstance = instance; } else { console.log('created時為', name, '沒有對應react實例'); wxInstances.push(this); } }, function attached() { if(appType == "ali"){ created.call(this) } if (this.reactInstance) { updateMiniApp(this.reactInstance); console.log('attached時更新', name); } else { console.log('attached時無法更新', name); } }, function detached() { this.reactInstance = null; }, ]; var data = { props: {}, state: {}, context: {}, }; var config = { data: data, public: data, dispatchEvent: eventSystem.dispatchEvent, methods: { dispatchEvent: eventSystem.dispatchEvent, }, }; hooksName[appType].forEach(function(name, index) { config[name] = hooks[index]; }); return config; } |