Mixin简介

Mixin(织入)模式并不是GOF的《设计模式》归纳中的一种,但是在各种语言以及框架都会发现该模式(或者思想)的一些应用。简单来说,Mixin是带有全部实现或者部分实现的接口,其主要作用是更好的代码复用。
Mixin这个概念在React, Vue中都有支持,它为我们抽象业务逻辑,代码复用提供了方便。然而小程序原生框架并没直接支持Mixin。我们先看一个很实际的需求:
为所有小程序页面增加运行环境class,以方便做一些样式hack。具体说就是小程序在不同的运行环境(开发者工具|iOS|Android)运行时,platform值为对应的运行环境值("ios|android|devtools")
<view class="{{platform}}">
<!--页面模板-->
</view>
回顾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分类
用代码表示的话,就如:
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等要想让mixin中的定义有效,就要在configObj正式传给Page()之前做文章。其实Page(configObj)就是一个普通的函数调用,我们加个中间方法:
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 = ['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 = 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;
};
小结
1、本文主要讲了如何为小程序增加mixin支持。实现思路为:预处理configObj
Page(createPage(configObj))
2、在处理mixin重复时,与vue保持一致:
data, methods会合并,组件自身具有最高优先级,其次mixins中后配置的mixin优先级较高。
lifecycle不会合并。先顺序执行mixins中的lifecycle,再执行组件自身的lifecycle。
总结
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# 微信小程序开发
# 微信小程序
# mixin
# 运行环境
# 都有
# 较高
# 先看
# 复用
# 会有
# 好了
# 多个
# 这就是
# 要在
# 我们可以
# 要想
# 发现该
# 这样做
# 做文章
# 问题是
# 可以直接
# 要让
# 这篇文章
# 谢谢大家
相关文章:
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
微课制作网站有哪些,微课网怎么进?
胶州企业网站制作公司,青岛石头网络科技有限公司怎么样?
寿县云建站:智能SEO优化与多行业模板快速上线指南
海南网站制作公司有哪些,海口网是哪家的?
如何通过虚拟主机快速完成网站搭建?
金*站制作公司有哪些,金华教育集团官网?
建站之星后台管理:高效配置与模板优化提升用户体验
广州营销型建站服务商推荐:技术优势与SEO优化解析
如何用PHP工具快速搭建高效网站?
宝塔建站后网页无法访问如何解决?
jQuery 常见小例汇总
北京专业网站制作设计师招聘,北京白云观官方网站?
淘宝制作网站有哪些,淘宝网官网主页?
平台云上自主建站:模板化设计与智能工具打造高效网站
如何快速上传自定义模板至建站之星?
PHP正则匹配日期和时间(时间戳转换)的实例代码
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
临沂网站制作企业,临沂第三中学官方网站?
宝塔面板创建网站无法访问?如何快速排查修复?
邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?
手机网站制作与建设方案,手机网站如何建设?
制作电商网页,电商供应链怎么做?
建站之星下载版如何获取与安装?
C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)
ppt制作免费网站有哪些,ppt模板免费下载网站?
建站之星好吗?新手能否轻松上手建站?
如何配置支付宝与微信支付功能?
制作证书网站有哪些,全国城建培训中心证书查询官网?
成都网站制作报价公司,成都工业用气开户费用?
,网站推广常用方法?
怎么将XML数据可视化 D3.js加载XML
制作网站的软件免费下载,免费制作app哪个平台好?
建站之星如何防范黑客攻击与数据泄露?
如何登录建站主机?访问步骤全解析
如何快速搭建高效WAP手机网站吸引移动用户?
网站制作价目表怎么做,珍爱网婚介费用多少?
三星网站视频制作教程下载,三星w23网页如何全屏?
建站之星代理如何优化在线客服效率?
交易网站制作流程,我想开通一个网站,注册一个交易网址,需要那些手续?
如何做网站制作流程,*游戏网站怎么搭建?
免费网站制作appp,免费制作app哪个平台好?
建站之星后台密码遗忘?如何快速找回?
网站插件制作软件免费下载,网页视频怎么下到本地插件?
制作网页的网站有哪些,电脑上怎么做网页?
制作假网页,招聘网的薪资待遇,会有靠谱的吗?一面试又各种折扣?
如何选择高性价比服务器搭建个人网站?
Python如何创建带属性的XML节点
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
制作旅游网站html,怎样注册旅游网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。