preface

The Toast or Message component is something that almost every project uses.

In Vue and React, they are components, and we tend to use these types of components to handle the global Api, so as to avoid having to write templates and data on every page and make it easier to use

Wx.showtoast () API has only success/loading two ways, which cannot meet our requirements.

Here’s the original…

<td-toast is-show="{{$toast.show}}" icon="{{$toast.icon}}" text="{{$toast.text}}"></td-toast>
Copy the code

{
  //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: ''
      }
    });
    //...省略其他逻辑
  }
}
Copy the code

The problem

Our business basically has toasts on every page. Does this mean that each page has to define WXML, data, toast(), clearToast()? We need a wx.showtoast () call

plan

We started with the WXML problem and found that it was not easy to solve. There was no way to create tags dynamically. WXML: create a plugin.wxml(to store all global common templates) and include the plugin.wxml in each page

//plugin.wxml

<! - currently only toast - > < td - toast is - show = "{{$toast. Show}}" icon = "{{$toast. Icon}}" text = "{{$toast. Text}}" > < / td - toast >Copy the code

Next deal with the js problem, to plugin.js to do plugin.wxml corresponding data logic

//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: ''
      }
    });
    //...省略其他逻辑
  }
};
Copy the code

Plugin.js is the content of the page, so the next step is to inject the content of plugin.js into each page.

This time we try to define an 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)
}
Copy the code

There is an inject method that adds plugin.js to the page. Just add inject method to the page

// pages/demo/index.js import inject from './.. /plugin/inject'; Page(// inject plugin inject({data: {}, onLoad: function(options) {}, onReady: function() {}, onShareAppMessage: Function () {// plugin.js () this.toast(' share ')}}));Copy the code

There are still some problems, such as the usingComponents field in JSON configuration. There is no good solution to these problems. Currently, we are writing a build tool to automatically handle JSON configuration, mainly for single file development. Handle NPM issues with additional support for PostCSS

That’s beside the point, we also use inject to do some other things, such as hook to page

For example, add the onLogin callback

//plugin.js export default { $data: { $toast: { show: false, text: '', icon: }}, /** * lifecycle function -- listen onLoad */ loadHooker: Function (onLoad, onLogin) {return function(option) {// onLoad. Call (this, option); const app = getApp(); If (app.globaldata.userinfo) {setTimeout(()=>{this.globalData = app.globalData; if (onLogin) { onLogin.call(this, option, app.globalData.userInfo); }} else {0} / / not login asynchronous = "onLogin app userInfoReadyCallback = json = > {this. GlobalData = app. GlobalData; if (onLogin) { onLogin.call(this, option, app.globalData.userInfo); }}; }}; }, toast(text, icon = '', times = 2000, cb) { //... Omit other logic}, clearToast() {//... Omit other logic}}; //inject.js import plugin from './plugin'; function inject(page) { for (let key in plugin.$data) { if (Object.prototype.hasOwnProperty.call(plugin.$data, {// filter page. Data [key] = plugin.$data[key]; }} // New callback 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) }Copy the code

If the FETCH interface depends on user information

Page( inject({ data: {}, onLoad: function() {}, onLogin: Function (options, userInfo) {this.toast(' get userInfo ') this.fetch(userinfo.openid); }}))Copy the code

Ok, this is a strange article to write for the first time. Any mistakes or better ideas to point out