微信小程序开发教程之增加mixin扩展

网友投稿 449 2023-04-22


微信小程序开发教程之增加mixin扩展

Mixin简介

Mixin(织入)模式并不是GOF的《设计模式》归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用。简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是更好的代码复用。

Mixin这个概念在React, vue中都有支持,它为我们抽象业务逻辑,代码复用提供了方便。然而小程序原生框架并没直接支持Mixin。我们先看一个很实际的需求:

为所有小程序页面增加运行环境class,以方便做一些样式hack。具体说就是小程序在不同的运行环境(开发者工具|iOS|android)运行时,platform值为对应的运行环境值("ios|android|devtools")

回顾vue中mixin的使用

文章开始提到的问题是非常适合使用Mixin来解决的。我们把这个需求转换成一个Vue问题:在每个路由页面中增加一个platform的样式class(虽然这样做可能没实际意义)。实现思路就是为每个路由组件增加一个data: platform。代码实现如下:

// mixins/platform.js

const getPlatform = () => {

// 具体实现略,这里mock返回'ios'

return 'ios';

};

export default {

data() {

return {

platform: getPlatform()

}

}

}

// 在路由组件中使用

// views/index.vue

import platform from 'mixins/platform';

export default {

mixins: [platform],

// ...

}

// 在路由组件中使用

// views/detail.vue

import platform from 'mixins/platform';

export default {

mixins: [platform],

// ...

}

这样,在index,detail两个路由页的viewModel上就都有platform这个值,可以直接在模板中使用。

vue中mixin分类

data mixin

normal method mixin

lifecycle method mixin

用代码表示的话,就如:

export default {

data () {

return {

platform: 'ios'

}

},

methods: {

sayHello () {

console.log(`hello!`)

}

},

created () {

console.log(`lifecycle3`)

}

}

vue中mixin合并,执行策略

如果mixin间出现了重复,这些mixin会有具体的合并,执行策略。如下图:

如何让小程序支持mixin

在前面,我们回顾了vue中mixin的相关知识。现在我们要让小程序也支持mixin,实现vue中一样的mixin功能。

实现思路

我们先看一下官方的小程序页面注册方式:

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: 'MINA'

}

})

假如我们加入mixin配置,上面的官方注册方式会变成:

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: 'MINA'

}

})

这里有两个点,我们要特别注意:

Page(configObj) - 通过configObj配置小程序页面的data, method, lifecycle等

onLoad方法 - 页面main入口

要想让mixin中的定义有效,就要在configObj正式传给Page()之前做文章。其实Page(configObj)就是一个普通的http://函数调用,我们加个中间方法:

Page(createPage(configObj))

在createPage这个方法中,我们可以预处理configObj中的mixin,把其中的配置按正确的方式合并到configObj上,最后交给Page() 。这就是实现mixin的思路。

具体实现

具体代码实现就不再赘述,可以看下面的代码。更详细的代码实现,更多扩展,测试可以参看github

/**

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

*/

const isArray = v => Array.isArray(v);

const isFunction = v => typeof v === 'function';

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 = [wRNaz'onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage'];

const APP_EVENT = ['onLaunch', 'onShow', 'onHide', 'onError'];

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 === 'onLoad') return;

ret[key] = methods[key];

}

});

// 提取lifecycle

PAGE_EVENT.forEach(key => {

if (isFunction(mixin[key]) && key !== 'onLoad') {

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 = nhttp://oop

} = 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;

};

小结

1、本文主要讲了如何为小程序增加mixin支持。实现思路为:预处理configObj

Page(createPage(configObj))

2、在处理mixin重复时,与vue保持一致:

data, methods会合并,组件自身具有最高优先级,其次mixins中后配置的mixin优先级较高。

lifecycle不会合并。先顺序执行mixins中的lifecycle,再执行组件自身的lifecycle。

总结

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对我们的支持。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:泛型接口的实现(分析泛型类,泛型接口,泛型方法的特点)
下一篇:网关api接口(api网关 bff)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~