Home  >  Article  >  WeChat Applet  >  Detailed explanation on adding mixin extensions in WeChat applet development

Detailed explanation on adding mixin extensions in WeChat applet development

黄舟
黄舟Original
2017-09-12 11:27:252295browse

Mixin is an idea that uses partially implemented interfaces to achieve code reuse. It can be used to solve the problem of multiple inheritance and can be used to extend functions. The following article mainly introduces you to the relevant information about adding mixin extensions to WeChat mini programs. Friends in need can refer to it. Let’s take a look together.

Introduction to Mixin

Mixin (weaving) mode is not one of GOF’s “Design Patterns” summary, but it is used in various Languages ​​and frameworks will find some application of this pattern (or idea). Simply put, Mixin is an interface with full or partial implementation, and its main function is better code reuse.

The concept of Mixin is supported in React and Vue. It provides convenience for us to abstract business logic and code reuse. However, the native mini program framework does not directly support Mixin. Let’s first look at a very practical requirement:

Add a running environment class to all mini program pages to facilitate some style hacks. Specifically, when the mini program is run in different operating environments (Developer Tools|iOS|Android), the platform value is the corresponding operating environment value ("ios|android|devtools")


<view class="{{platform}}">
 <!--页面模板-->
</view>

Reviewing the use of mixin in vue

The problems mentioned at the beginning of the article are very suitable to be solved using Mixin. We converted this requirement into a Vue problem: add a platform style class to each routing page (although this may not be practical). The implementation idea is to add a data: platform to each routing component. The code is implemented as follows:


// mixins/platform.js
const getPlatform = () => {
 // 具体实现略,这里mock返回&#39;ios&#39;
 return &#39;ios&#39;;
};

export default {
 data() {
 return {
  platform: getPlatform()
 }
 }
}


// 在路由组件中使用
// views/index.vue
import platform from &#39;mixins/platform&#39;;

export default {
 mixins: [platform],
 // ...
}


// 在路由组件中使用
// views/detail.vue
import platform from &#39;mixins/platform&#39;;
export default {
 mixins: [platform],
 // ...
}

In this way, in the index and detail routing pages The viewModel has the platform value, which can be used directly in the template.

mixin classification in vue

  • data mixin

  • ##normal method mixin

  • lifecycle method mixin

If expressed in code, it would be like:


export default {
 data () {
 return {
  platform: &#39;ios&#39;
 }
 },
 methods: {
 sayHello () {
  console.log(`hello!`)
 }
 },

 created () {
 console.log(`lifecycle3`)
 }
}

Mixin merging and execution strategies in vue

If there are duplications between mixins, these mixins will have specific merging and execution strategies. As shown below:

How to make the applet support mixin

In front, we reviewed vue Knowledge about mixins. Now we need to make the mini program also support mixin and realize the same mixin function in vue.

Implementation ideas

Let’s first take a look at the official mini program page registration method:


Page({
 data: {
 text: "This is page data."
 },
 onLoad: function(options) {
 // Do some initialize when page load.
 },
 onReady: function() {
 // Do something when page ready.
 },
 onShow: function() {
 // Do something when page show.
 },
 onHide: function() {
 // Do something when page hide.
 },
 onUnload: function() {
 // Do something when page close.
 },
 customData: {
 hi: &#39;MINA&#39;
 }
})

If we Adding mixin configuration, the above official registration method will become:


Page({
 mixins: [platform],
 data: {
 text: "This is page data."
 },
 onLoad: function(options) {
 // Do some initialize when page load.
 },
 onReady: function() {
 // Do something when page ready.
 },
 onShow: function() {
 // Do something when page show.
 },
 onHide: function() {
 // Do something when page hide.
 },
 onUnload: function() {
 // Do something when page close.
 },
 customData: {
 hi: &#39;MINA&#39;
 }
})

There are two points here that we should pay special attention to:

  • Page(configObj) - Configure the data, method, lifecycle, etc. of the applet page through configObj

  • onLoad method - page main entrance

If you want the definition in the mixin to be valid, you must make a fuss before configObj is officially passed to

Page(). In fact, Page(configObj) is an ordinary function call. We add an intermediate method:


Page(createPage(configObj))

In the createPage method, we can preprocess The mixin in configObj merges the configuration into configObj in the correct way, and finally hands it to

Page() . This is the idea of ​​​​implementing mixins.

Specific implementation

The specific code implementation will not be described in detail. You can see the following code. For more detailed code implementation, more extensions, and tests, please refer to github


/**
 * 为每个页面提供mixin,page invoke桥接
 */

const isArray = v => Array.isArray(v);
const isFunction = v => typeof v === &#39;function&#39;;
const noop = function () {};

// 借鉴redux https://github.com/reactjs/redux
function compose(...funcs) {
 if (funcs.length === 0) {
 return arg => arg;
 }

 if (funcs.length === 1) {
 return funcs[0];
 }

 const last = funcs[funcs.length - 1];
 const rest = funcs.slice(0, -1);
 return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));
}


// 页面堆栈
const pagesStack = getApp().$pagesStack;

const PAGE_EVENT = [&#39;onLoad&#39;, &#39;onReady&#39;, &#39;onShow&#39;, &#39;onHide&#39;, &#39;onUnload&#39;, &#39;onPullDownRefresh&#39;, &#39;onReachBottom&#39;, &#39;onShareAppMessage&#39;];
const APP_EVENT = [&#39;onLaunch&#39;, &#39;onShow&#39;, &#39;onHide&#39;, &#39;onError&#39;];

const onLoad = function (opts) {
 // 把pageModel放入页面堆栈
 pagesStack.addPage(this);

 this.$invoke = (pagePath, methodName, ...args) => {
 pagesStack.invoke(pagePath, methodName, ...args);
 };

 this.onBeforeLoad(opts);
 this.onNativeLoad(opts);
 this.onAfterLoad(opts);
};

const getMixinData = mixins => {
 let ret = {};

 mixins.forEach(mixin => {
 let { data={} } = mixin;

 Object.keys(data).forEach(key => {
  ret[key] = data[key];
 });
 });

 return ret;
};

const getMixinMethods = mixins => {
 let ret = {};

 mixins.forEach(mixin => {
 let { methods={} } = mixin;

 // 提取methods
 Object.keys(methods).forEach(key => {
  if (isFunction(methods[key])) {
  // mixin中的onLoad方法会被丢弃
  if (key === &#39;onLoad&#39;) return;

  ret[key] = methods[key];
  }
 });

 // 提取lifecycle
 PAGE_EVENT.forEach(key => {
  if (isFunction(mixin[key]) && key !== &#39;onLoad&#39;) {
  if (ret[key]) {
   // 多个mixin有相同lifecycle时,将方法转为数组存储
   ret[key] = ret[key].concat(mixin[key]);
  } else {
   ret[key] = [mixin[key]];
  }
  }
 })
 });

 return ret;
};

/**
 * 重复冲突处理借鉴vue:
 * data, methods会合并,组件自身具有最高优先级,其次mixins中后配置的mixin优先级较高
 * lifecycle不会合并。先顺序执行mixins中的lifecycle,再执行组件自身的lifecycle
 */

const mixData = (minxinData, nativeData) => {
 Object.keys(minxinData).forEach(key => {
 // page中定义的data不会被覆盖
 if (nativeData[key] === undefined) {
  nativeData[key] = minxinData[key];
 }
 });

 return nativeData;
};

const mixMethods = (mixinMethods, pageConf) => {
 Object.keys(mixinMethods).forEach(key => {
 // lifecycle方法
 if (PAGE_EVENT.includes(key)) {
  let methodsList = mixinMethods[key];

  if (isFunction(pageConf[key])) {
  methodsList.push(pageConf[key]);
  }

  pageConf[key] = (function () {
  return function (...args) {
   compose(...methodsList.reverse().map(f => f.bind(this)))(...args);
  };
  })();
 }

 // 普通方法
 else {
  if (pageConf[key] == null) {
  pageConf[key] = mixinMethods[key];
  }
 }
 });

 return pageConf;
};

export default pageConf => {

 let {
 mixins = [],
 onBeforeLoad = noop,
 onAfterLoad = noop
 } = pageConf;

 let onNativeLoad = pageConf.onLoad || noop;
 let nativeData = pageConf.data || {};

 let minxinData = getMixinData(mixins);
 let mixinMethods = getMixinMethods(mixins);

 Object.assign(pageConf, {
 data: mixData(minxinData, nativeData),
 onLoad,
 onBeforeLoad,
 onAfterLoad,
 onNativeLoad,
 });

 pageConf = mixMethods(mixinMethods, pageConf);

 return pageConf;
};

Summary

1 , This article mainly talks about how to add mixin support to small programs. The implementation idea is: preprocessing configObj



Page(createPage(configObj))

2. When dealing with mixin duplication, be consistent with vue:

data, methods will be merged , the component itself has the highest priority, and the mixin configured later in the mixins has a higher priority.


lifecycle will not be merged. First execute the lifecycle in the mixins sequentially, and then execute the lifecycle of the component itself.

Summarize

The above is the detailed content of Detailed explanation on adding mixin extensions in WeChat applet development. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn