Abstract: Small program development skills

  • Author: jrainlau
  • Implement Mixins schemes in applets

FundebugReproduced with authorization, copyright belongs to the original author.

In the process of developing applets natively, you find that there are multiple pages that use almost exactly the same logic. Since applets do not officially provide a mechanism for code reuse like Mixins, they have to “reuse” code in a very inelegant copy-and-paste way. As functionality became more complex, it became unscientific to maintain code by copying and pasting, so I began to think about how to implement Mixins in small programs.

What is a Mixins

Mixins literally mean “mix”, and as the name implies, mix reusable code into current code. Those familiar with VueJS should know that it provides more powerful code reuse capability, decouples duplicate modules, and makes system maintenance more convenient and elegant.

Let’s take a look at how Mixins are used in VueJS.

// define a mixin object
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin! ')}}}// define a component that uses this mixin
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component() // => "hello from mixin!"
Copy the code

In the above code, we first define an object called myMixin, which defines some lifecycle functions and methods. It is then injected directly into a newly created component through mixins: [myMixin], which then gets the methods from myMixin.

Once you understand what Mixins are, you can start implementing them in applets.

The mechanism of Mixins

Mixins also have a few minor details to pay attention to, regarding the order in which lifecycle events are executed. In the example in the previous section, we defined an Created () method in myMixin, which is a lifecycle event in VueJS. What if we also defined a created() method in the new Component?

var Component = Vue.extend({
  mixins: [myMixin],
  created: function () {
    console.log('hello from Component! ')}})var component = new Component()

/ / = >
// Hello from mixin!
// Hello from Component!
Copy the code

As you can see, the result is to output the logs from the Mixin first, and then the logs from the component.

In addition to lifecycle functions, consider the mixed results of object attributes:

// define a mixin object
const myMixin = {
  data () {
    return {
      mixinData: 'data from mixin'}}}// define a component that uses this mixin
var Component = Vue.extend({
  mixins: [myMixin],
  data () {
    return {
      componentData: 'data from component'
    }
  },
  mounted () {
    console.log(this.$data)
  }
})

var component = new Component()
Copy the code

In VueJS, content from Mixins and component object properties (data, methods, etc.) are mixed to ensure that data exists on both sides.

After the above verification, we can get the conclusion about the operation mechanism of Mixins in VueJS:

  1. The lifecycle property executes first those from Mixins and then those from components.
  2. Object type attributes, from Mixins and from components, coexist.

But in applets, this mechanism is a little different from VueJS. In applets, custom methods are defined directly in Page properties and are neither lifecycle type nor object type properties. In order not to introduce strange problems, we add one more rule to the Mixins running mechanism of applets:

  1. The custom methods in the applet have precedence of Page > Mixins, that is, the custom methods in the Page will override the ones in the Mixins.

Code implementation

In applets, each Page is defined by the Page(options) function, and Mixins operate on the Options object in that function. So here’s the idea for Mixins: hijack and rewrite the Page function, then release it again.

Create a new mixins.js file:

// Save the native Page function
const originPage = Page

Page = (options) = > {
  const mixins = options.mixins
  // Mixins must be arrays
  if (Array.isArray(mixins)) {
    delete options.mixins
    // Mixins inject and execute the corresponding logic
    options = merge(mixins, options)
  }
  // Release the native Page function
  originPage(options)
}
Copy the code

The principle is simple, but the key is the merge() function. The merge function is a concrete implementation of the Mixins running mechanism for small programs, following exactly the three conclusions summarized in the previous section.

// Define attributes/methods built into the applet
const originProperties = ['data'.'properties'.'options']
const originMethods = ['onLoad'.'onReady'.'onShow'.'onHide'.'onUnload'.'onPullDownRefresh'.'onReachBottom'.'onShareAppMessage'.'onPageScroll'.'onTabItemTap']

function merge (mixins, options) {
  mixins.forEach((mixin) = > {
    if (Object.prototype.toString.call(mixin) ! = ='[object Object]') {
      throw new Error('Mixin type must be an object! ')}// Iterate over all mixin attributes
    for (let [key, value] of Object.entries(mixin)) {
      if (originProperties.includes(key)) {
        // Built-in object attributes are mixed inoptions[key] = { ... value, ... options[key] } }else if (originMethods.includes(key)) {
        // The built-in method attributes are mixed, and the mixed parts are executed first
        const originFunc = options[key]
        options[key] = function (. args) {
          value.call(this. args)return originFunc && originFunc.call(this. args) } }else {
        // Custom methods are mixed inoptions = { ... mixin, ... options } } } })return options
}
Copy the code

Mixins using

  1. Add mixins.js to the applet’s app.js

    require('./mixins.js')
    Copy the code
  2. Write a mymixin.js

    module.exports = {
      data: { someData: 'myMixin' },
      onShow () { console.log('Log from mixin! ')}}Copy the code
  3. Used in page/index/index.js

    Page({
      mixins: [require('.. /.. /myMixin.js')]})Copy the code

And you’re done! At this point, the small program already has Mixins capability, which will be more convenient for code decoupling and reuse.

About Fundebug

Fundebug focuses on real-time BUG monitoring for JavaScript, wechat applets, wechat games, Alipay applets, React Native, Node.js and Java online applications. Since its official launch on November 11, 2016, Fundebug has handled over 1 billion error events in total, and paid customers include Sunshine Insurance, Walnut Programming, Lychee FM, Zhangmen 1-to-1, Weimai, Qingtuanshe and many other brand enterprises. Welcome to try it for free!