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