### [微信小程序开发教程之增加mixin扩展](https://www.prosaas.cn/article/17436) **Published:** 2018-06-23T01:37:02 **Author:** 5201314 **Excerpt:** 这篇文章主要介绍了关于微信小程序开发教程之增加mixin扩展,有着一定的参考价值,现在分享给大家,有需要的朋友… 这篇文章主要介绍了关于微信小程序开发教程之增加mixin扩展,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下 Mixin是一种思想,用部分实现的接口来实现代码复用。可以用来解决多继承的问题,又可以用来扩展功能。下面这篇文章主要给大家介绍了关于为微信小程序增加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会有具体的合并,执行策略。如下图: ![](https://img.php.cn/upload/article/000/000/009/8ba168ac12d164835c2e801168f3c91c-0.png) **如何让小程序支持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)`就是一个普通的函数调用,我们加个中间方法: 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。 以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网! 相关推荐: 微信小程序中跳转页面的两种方法 微信开发之js实现tabs选项卡效果 以上就是微信小程序开发教程之增加mixin扩展的详细内容,更多请关注知企PROSAAS其它相关文章! **Tags:** android, class, github, ios, JS, php, 多继承, 微信小程序, 接口, 继承 **Categories:** 后端开发 ---