前言toast 或 message 組件,基本是每個項目都會使用到的。 在Vue、React中它們都是組件,而我們習(xí)慣將這類型的組件處理全局Api,以避免每個頁面都要寫 template 以及 data,更加方便使用 而在小程序中,自定義組件 Toast 也有同樣的問題[wx.showToast() 這個 api 只有 success/loading 兩種方式,無法滿足我們的需求] 原版是這樣… <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>
問題
我們的業(yè)務(wù)基本上每個頁面都會有 toast。這意味著每個 page 都得去定義wxml、data、toast()、clearToast() ? 方案
我們先處理wxml的問題,發(fā)現(xiàn)這個問題并不好解決,我們沒有辦法動態(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>
接下來處理js 的問題,來個 plugin.js 來做plugin.wxml對應(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>
能看出來其實plugin.js就是page的內(nèi)容,那下一步需要做的就是吧plugin.js的內(nèi)容注入到每個page中。 這時候嘗試著定義了一個inject.js import plugin from './plugin'; function inject(page) { for (let key in plugin.$data) { if (Object.prototype.hasOwnProperty.call(plugin.$data, key)) { //過濾 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>
這時候有了個 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)然還有一些問題,比如說json配置中的 usingComponents 字段 這是題外話了,上面的inject 我們還能用來做一些其他的事情,比如對page的hook 例如:增加onLogin回調(diào) //plugin.js export default { $data: { $toast: { show: false, text: '', icon: '' } }, /** * 生命周期函數(shù)--監(jiān)聽onLoad */ loadHooker: function(onLoad, onLogin) { return function(option) { // 不管三七二十一 先調(diào)了onLoad再說 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 { //沒有登錄 異步=》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)) { //過濾 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); } }) )
好吧 第一次寫這種文章 挺生疏,有什么錯誤或者有更好的思路希望能指出 |
工作日 8:30-12:00 14:30-18:00
周六及部分節(jié)假日提供值班服務(wù)