如何在微信小程序中实现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 相关文章推荐
jqueyr判断checkbox组的选中(示例代码)
Nov 08 Javascript
js打开windows上的可执行文件示例
May 27 Javascript
JS动态修改iframe内嵌网页地址的方法
Apr 01 Javascript
性能优化之代码优化页面加载速度
Mar 01 Javascript
React复制到剪贴板的示例代码
Aug 22 Javascript
Vue官方文档梳理之全局配置
Nov 22 Javascript
form表单数据封装成json格式并提交给服务器的实现方法
Dec 14 Javascript
AngularJs分页插件使用详解
Jun 30 Javascript
vue.js配合$.post从后台获取数据简单demo分享
Aug 11 Javascript
Vue文件配置全局变量的实例
Sep 06 Javascript
原生javascript实现连连看游戏
Jan 03 Javascript
bootstrap-table实现表头固定以及列固定的方法示例
Mar 07 Javascript
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 fputcsv命令 写csv文件遇到的小问题(多维数组连接符)
2011/05/24 PHP
phpmailer在服务器上不能正常发送邮件的解决办法
2014/07/08 PHP
PHP实现的下载远程图片自定义函数分享
2015/01/28 PHP
PHP基于socket实现客户端和服务端通讯功能
2017/07/13 PHP
php取出数组单个值的方法
2018/03/12 PHP
PHP的mysqli_set_charset()函数讲解
2019/01/23 PHP
DEFER怎么用?
2006/07/01 Javascript
超清晰的document对象详解
2007/02/27 Javascript
javascript 语法基础 想学习js的朋友可以看看
2009/12/16 Javascript
JS 实现导航栏悬停效果(续)
2013/09/24 Javascript
SeaJS入门教程系列之使用SeaJS(二)
2014/03/03 Javascript
自写的jQuery异步加载数据添加事件
2014/05/15 Javascript
使用AngularJS实现可伸缩的页面切换的方法
2015/06/19 Javascript
AngularJS 实现按需异步加载实例代码
2015/10/18 Javascript
CodeMirror js代码加亮使用总结
2017/03/25 Javascript
JavaScript数据结构之数组的表示方法示例
2017/04/12 Javascript
Angular2管道Pipe及自定义管道格式数据用法实例分析
2017/11/29 Javascript
vue实现导航栏效果(选中状态刷新不消失)
2017/12/13 Javascript
JavaScript实现微信号随机切换代码
2018/03/09 Javascript
微信小程序自定义底部弹出框
2020/11/16 Javascript
Vue中 v-if/v-show/插值表达式导致闪现的原因及解决办法
2018/10/12 Javascript
Vue实现移动端页面切换效果【推荐】
2018/11/13 Javascript
Jquery滑动门/tab切换实现方法完整示例
2020/06/05 jQuery
[02:03]《现实生活中的DOTA2》—林书豪&DOTA2职业选手出演短片
2015/08/18 DOTA
详解Python中的多线程编程
2015/04/09 Python
Python中正则表达式详解
2017/05/17 Python
python编程线性回归代码示例
2017/12/07 Python
docker-py 用Python调用Docker接口的方法
2019/08/30 Python
Python爬虫使用代理IP的实现
2019/10/27 Python
详谈tensorflow gfile文件的用法
2020/02/05 Python
Python使用进程Process模块管理资源
2020/03/05 Python
Python多线程threading创建及使用方法解析
2020/06/17 Python
美国领先的在线邮轮旅游公司:CruiseDirect
2018/06/07 全球购物
《爱的教育》读书心得
2014/11/08 职场文书
学雷锋献爱心活动总结
2015/05/11 职场文书
环保建议书作文300字
2015/09/14 职场文书