前言toast 或 message 組件,基本是每個(gè)項(xiàng)目都會(huì)使用到的。 在Vue、React中它們都是組件,而我們習(xí)慣將這類型的組件處理全局Api,以避免每個(gè)頁(yè)面都要寫 template 以及 data,更加方便使用 而在小程序中,自定義組件 Toast 也有同樣的問(wèn)題[wx.showToast() 這個(gè) api 只有 success/loading 兩種方式,無(wú)法滿足我們的需求] 原版是這樣…
<td-toast is-show="{{$toast.show}}" icon="{{$toast.icon}}" text="{{$toast.text}}"></td-toast>
{
//data
data:{
$toast: {
show: false,
text: '',
icon: ''
}
},
//methods
toast(text, icon = '', times = 2000, cb) {
//...省略其他邏輯
this.setData({
$toast: {
show: true,
text: text,
icon: icon
}
});
//...省略其他邏輯
},
clearToast() {
//...省略其他邏輯
this.setData({
$toast: {
show: false,
text: '',
icon: ''
}
});
//...省略其他邏輯
}
}
<div class="md-section-divider"></div>
問(wèn)題
我們的業(yè)務(wù)基本上每個(gè)頁(yè)面都會(huì)有 toast。這意味著每個(gè) page 都得去定義wxml、data、toast()、clearToast() ? 方案
我們先處理wxml的問(wèn)題,發(fā)現(xiàn)這個(gè)問(wèn)題并不好解決,我們沒(méi)有辦法動(dòng)態(tài)的創(chuàng)建標(biāo)簽。 //plugin.wxml
<!-- 目前只有toast -->
<td-toast is-show="{{$toast.show}}" icon="{{$toast.icon}}" text="{{$toast.text}}"></td-toast>
<div class="md-section-divider"></div>
接下來(lái)處理js 的問(wèn)題,來(lái)個(gè) plugin.js 來(lái)做plugin.wxml對(duì)應(yīng)的數(shù)據(jù)邏輯 //plugin.js
export default {
$data: {
$toast: {
show: false,
text: '',
icon: ''
}
},
//methods
toast(text, icon = '', times = 2000, cb) {
//...省略其他邏輯
this.setData({
$toast: {
show: true,
text: text,
icon: icon
}
});
//...省略其他邏輯
},
clearToast() {
//...省略其他邏輯
this.setData({
$toast: {
show: false,
text: '',
icon: ''
}
});
//...省略其他邏輯
}
};
<div class="md-section-divider"></div>
能看出來(lái)其實(shí)plugin.js就是page的內(nèi)容,那下一步需要做的就是吧plugin.js的內(nèi)容注入到每個(gè)page中。 這時(shí)候嘗試著定義了一個(gè)inject.js
import plugin from './plugin';
function inject(page) {
for (let key in plugin.$data) {
if (Object.prototype.hasOwnProperty.call(plugin.$data, key)) { //過(guò)濾
page.data[key] = plugin.$data[key];
}
}
const obj = Object.assign({}, plugin, page);
return obj;
}
export default (page) => {
return inject(page)
}
<div class="md-section-divider"></div>
這時(shí)候有了個(gè) inject方法能把 plugin.js合并到page了。
// pages/demo/index.js
import inject from './../plugin/inject';
Page(
// 注入 plugin
inject({
data: {},
onLoad: function(options) {},
onReady: function() {},
onShareAppMessage: function() {
// plugin.js中定義的 toast()
this.toast('分享')
}
})
);
<div class="md-section-divider"></div>
到這里就差不多基本完成了,當(dāng)然還有一些問(wèn)題,比如說(shuō)json配置中的 usingComponents 字段 這是題外話了,上面的inject 我們還能用來(lái)做一些其他的事情,比如對(duì)page的hook 例如:增加onLogin回調(diào)
//plugin.js
export default {
$data: {
$toast: {
show: false,
text: '',
icon: ''
}
},
/**
* 生命周期函數(shù)--監(jiān)聽(tīng)onLoad
*/
loadHooker: function(onLoad, onLogin) {
return function(option) {
// 不管三七二十一 先調(diào)了onLoad再說(shuō)
onLoad.call(this, option);
const app = getApp();
if (app.globalData.userInfo) { // 已經(jīng)登錄
setTimeout(()=>{
this.globalData = app.globalData;
if (onLogin) {
onLogin.call(this, option, app.globalData.userInfo);
}
},0)
} else { //沒(méi)有登錄 異步=》onLogin
app.userInfoReadyCallback = json => {
this.globalData = app.globalData;
if (onLogin) {
onLogin.call(this, option, app.globalData.userInfo);
}
};
}
};
},
toast(text, icon = '', times = 2000, cb) {
//...省略其他邏輯
},
clearToast() {
//...省略其他邏輯
}
};
//inject.js
import plugin from './plugin';
function inject(page) {
for (let key in plugin.$data) {
if (Object.prototype.hasOwnProperty.call(plugin.$data, key)) { //過(guò)濾
page.data[key] = plugin.$data[key];
}
}
//新回調(diào)
const onLoadHooker = plugin.loadHooker(page.onLoad, page.onLogin);
const obj = Object.assign({}, plugin, page);
obj.onLoad = onLoadHooker;// hookonLoad
return obj;
}
export default (page) => {
return inject(page)
}
<div class="md-section-divider"></div>
如果fetch接口依賴于用戶信息
Page(
inject({
data: {},
onLoad: function() {},
onLogin: function(options, userInfo) {
this.toast('拿到用戶信息')
this.fetch(userInfo.openid);
}
})
)
好吧 第一次寫這種文章 挺生疏,有什么錯(cuò)誤或者有更好的思路希望能指出 |