如何在微信小程序中实现Mixins方案


Posted in Javascript onJune 20, 2019

前言

在原生开发小程序的过程中,发现有多个页面都使用了几乎完全一样的逻辑。由于小程序官方并没有提供 Mixins 这种代码复用机制,所以只能采用非常不优雅的复制粘贴的方式去“复用”代码。随着功能越来越复杂,靠复制粘贴来维护代码显然不科学,于是便寻思着如何在小程序里面实现 Mixins。

什么是 Mixins

Mixins 直译过来是“混入”的意思,顾名思义就是把可复用的代码混入当前的代码里面。熟悉 VueJS 的同学应该清楚,它提供了更强大了代码复用能力,解耦了重复的模块,让系统维护更加方便优雅。

先看看在 VueJS 中是怎么使用 Mixins 的。

// 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!"

在上述的代码中,首先定义了一个名为 myMixin 的对象,里面定义了一些生命周期函数和方法。接着在一个新建的组件里面直接通过 mixins: [myMixin] 的方式注入,此时新建的组件便获得了来自 myMixin 的方法了。

明白了什么是 Mixins 以后,便可开始着手在小程序里面实现了。

Mixins 的机制

Mixins 也有一些小小的细节需要注意的,就是关于生命周期事件的执行顺序。在上一节的例子中,我们在 myMixin 里定义了一个 created() 方法,这是 VueJS 里面的一个生命周期事件。如果我们在新建组件 Component 里面也定义一个 created() 方法,那么执行结果会是如何呢?

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

var component = new Component()

// =>
// Hello from mixin!
// Hello from Component!

可以看运行结果是先输出了来自 Mixin 的 log,再输出来自组件的 log。

除了生命周期函数以外,再看看对象属性的混入结果:

// 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()

如何在微信小程序中实现Mixins方案

在 VueJS 中,会把来自 Mixins 和组件的对象属性当中的内容(如 data, methods等)混合,以确保两边的数据都同时存在。

经过上述的验证,我们可以得到 VueJS 中关于 Mixins 运行机制的结论:

  • 生命周期属性,会优先执行来自 Mixins 当中的,后执行来自组件当中的。
  • 对象类型属性,来自 Mixins 和来自组件中的会共存。

但是在小程序中,这套机制会和 VueJS 的有一点区别。在小程序中,自定义的方法是直接定义在 Page 的属性当中的,既不属于生命周期类型属性,也不属于对象类型属性。为了不引入奇怪的问题,我们为小程序的 Mixins 运行机制多加一条:

  • 小程序中的自定义方法,优先级为 Page > Mixins,即 Page 中的自定义方法会覆盖 Mixins 当中的。

代码实现

在小程序中,每个页面都由 Page(options) 函数定义,而 Mixins 则作用于这个函数当中的 options 对象。因此我们实现 Mixins 的思路就有了——劫持并改写 Page 函数,最后再重新把它释放出来。

新建一个 mixins.js 文件:

// 保存原生的 Page 函数
const originPage = Page

Page = (options) => {
 const mixins = options.mixins
 // mixins 必须为数组
 if (Array.isArray(mixins)) {
 delete options.mixins
 // mixins 注入并执行相应逻辑
 merge(mixins, options)
 }
 // 释放原生 Page 函数
 originPage(options)
}

原理很简单,关键的地方在于 merge() 函数。merge 函数即为小程序 Mixins 运行机制的具体实现,完全按照上一节总结的三条结论来进行。

// 定义小程序内置的属性/方法
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 类型必须为对象!')
 }
 // 遍历 mixin 里面的所有属性
 for (let [key, value] of Object.entries(mixin)) {
  if (originProperties.includes(key)) {
  // 内置对象属性混入
  options[key] = { ...value, ...options[key] }
  } else if (originMethods.includes(key)) {
  // 内置方法属性混入,优先执行混入的部分
  const originFunc = options[key]
  options[key] = function (...args) {
   value.call(this, ...args)
   return originFunc && originFunc.call(this, ...args)
  }
  } else {
  // 自定义方法混入
  options = { ...mixin, ...options }
  }
 }
 })
}

Mixins 使用

在小程序的 app.js 里引入 mixins.js

require('./mixins.js')

撰写一个 myMixin.js

module.exports = {
 data: { someData: 'myMixin' },
 onShow () { console.log('Log from mixin!') }
}

在 page/index/index.js 中使用

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

如何在微信小程序中实现Mixins方案

大功告成!此时小程序已经具备 Mixins 的能力,对于代码解耦与复用来说将会更加方便。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
使用JS读秒使用示例
Sep 21 Javascript
删除节点的jquery代码
Jan 13 Javascript
js 删除数组的几种方法小结
Feb 21 Javascript
js操作输入框中选择内容兼容IE及其他主流浏览器
Apr 22 Javascript
JQuery仿小米手机抢购页面倒计时效果
Dec 16 Javascript
jQuery时间轴插件使用详解
Jul 16 Javascript
React实现点击删除列表中对应项
Jan 10 Javascript
Angular指令封装jQuery日期时间插件datetimepicker实现双向绑定示例
Jan 22 Javascript
在ABP框架中使用BootstrapTable组件的方法
Jul 31 Javascript
JS设计模式之策略模式概念与用法分析
Feb 05 Javascript
layui监听下拉选框选中值变化的方法(包含监听普通下拉选框)
Sep 24 Javascript
jQuery实现滑动星星评分效果(每日分享)
Nov 13 jQuery
js JSON.stringify()基础详解
Jun 19 #Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
Jun 19 #jQuery
Vue-Cli 3.0 中配置高德地图的两种方式
Jun 19 #Javascript
vue axios重复点击取消上一次请求封装的方法
Jun 19 #Javascript
javascript创建元素和删除元素实例小结
Jun 19 #Javascript
Vue 2.0 侦听器 watch属性代码详解
Jun 19 #Javascript
js获取对象,数组所有属性键值(key)和对应值(value)的方法示例
Jun 19 #Javascript
You might like
php 判断数组是几维数组
2013/03/20 PHP
php实现格式化多行文本为Js可用格式
2015/04/15 PHP
PHP5.4起内置web服务器使用方法
2016/08/09 PHP
PHP底层运行机制与工作原理详解
2020/07/31 PHP
JS延迟加载(setTimeout) JS最后加载
2010/07/15 Javascript
基于jquery的弹出提示框始终处于窗口的居中位置(类似于alert弹出框的效果)
2011/09/28 Javascript
Nodejs学习笔记之Global Objects全局对象
2015/01/13 NodeJs
jQuery实现延迟跳转的方法
2015/06/05 Javascript
兼容各大浏览器的JavaScript阻止事件冒泡代码
2015/07/09 Javascript
jquery移动端TAB触屏切换实现效果
2020/12/22 Javascript
js实现的星星评分功能函数
2015/12/09 Javascript
JavaScript使用readAsDataUrl方法预览图片
2017/05/10 Javascript
Node.js利用断言模块assert进行单元测试的方法
2017/09/28 Javascript
JS基于Location实现访问Url、重定向及刷新页面的方法分析
2018/12/03 Javascript
Vue 事件处理操作实例详解
2019/03/05 Javascript
jsonp跨域获取百度联想词的方法分析
2019/05/13 Javascript
wx-charts 微信小程序图表插件的具体使用
2019/08/18 Javascript
jQuery 动画与停止动画效果实例详解
2020/05/19 jQuery
vue自定义插件封装,实现简易的elementUi的Message和MessageBox的示例
2020/11/20 Vue.js
React服务端渲染原理解析与实践
2021/03/04 Javascript
python中pygame模块用法实例
2014/10/09 Python
Python采用socket模拟TCP通讯的实现方法
2014/11/19 Python
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
Python3中的2to3转换工具使用示例
2015/06/12 Python
python实现线程池的方法
2015/06/30 Python
Python交互环境下实现输入代码
2018/06/22 Python
python pygame实现五子棋小游戏
2020/10/26 Python
python的命名规则知识点总结
2019/10/04 Python
JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?
2015/10/22 面试题
销售人员自我评价怎么写
2013/09/19 职场文书
计算机专业个人简短的自我评价
2013/10/23 职场文书
重大事项社会稳定风险评估方案
2014/06/15 职场文书
幼儿园大班开学寄语
2014/08/02 职场文书
民族学专业职业生涯规划范文:积跬步以至千里
2014/09/11 职场文书
学生会部长竞选稿
2015/11/19 职场文书
Python自动化工具之实现Excel转Markdown表格
2022/04/08 Python