熟悉 Vue 的同学对 computed
和 watch
一定很熟悉,这些特性大大方便了我们对代码中的数据进行处理:
var vm = new Vue({
el: '#example',data: {
message: 'Hello'
},computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
复制代码
var vm = new Vue({
el: '#demo',data: {
firstName: 'Foo',lastName: 'Bar',fullName: 'Foo Bar'
},watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
复制代码
这是 Vue 官网中两段代码。
官方实现
如今小程序也有了自己的实现,详见官方文档 observer 。小程序官方 github
中也开源了通过 Behaviors 实现的 Vue 风格的computed
和watch
:github.com/wechat-mini…。
那么在微信没有提供这些方法之前,如何自主实现数据的侦听器和计算属性呢?
自主实现
先看看定义的使用文档:
Page({
data: {
list: [],list2: [],size: 0
},// 侦听器函数名必须跟需要被侦听的 data 对象中的属性同名,
// 其参数中的 newValue 为属性改变后的新值,oldValue 为改变前的旧值
watch: {
// 如果 `list` 发生改变,这个函数就会运行
list(newValue,oldValue) {
console.log(oldValue + '=>' + newValue)
}
},// 传入的参数list必须是 data 里面的属性
// 这里可以传入多个 data 属性
computed({
list,list2
}) {
return {
size: list.length,size2: list2.length
}
}
})
复制代码
在 Page
的传参中多了两个熟悉的属性,用法不用解释太多。需要继续对小程序提供的 Page
方法进行改造,此外,因为所有数据变化都会用到 setData
方法去触发,所以还需要改造这个方法。
改造 Page 和 setData
想要基于原有的 setData
进行封装,那就得先得到这个函数缓存下来(像是缓存原有的 Page
一样)。想到 onLoad
是小程序页面的第一个生命周期函数,可以在这里进行操作:
// 缓存原有的 `Page`
let originPage = Page
// 定义新的 Page
function MyPage(config) {
let that = this
this.watch = config.watch
this.computed = config.computed
this.lifetimeBackup = {
onLoad: config.onLoad
}
config.onLoad = function(options) {
// 缓存下原有的 `setData`
this._setData = this.setData.bind(this)
this.setData = (data) => {
// 侦听器
that.watching(data)
// 计算器
let newData = that.getComputedData(data)
this._setData(extend(data,newData))
}
// 备份下页面实例
that.context = this
// 执行真正的 `onLoad`
this.lifetimeBackup.onLoad.call(this,options)
}
// ...
originPage(config)
}
MyPage.prototype.watching = funtion(data) {
// 执行侦听器
// ...
}
// 计算器
MyPage.prototype.getComputedData = function(data) {
// 开始生成新的数据
// ...
}
function page (config) {
return new MyPage(config)
}
复制代码
大致代码如上,重新定义了 this.setData
,备份了原有的 setData
到 this._setData
。当然,这里只考虑了 setData
传一个参数的情况,多个参数需要再对代码优化下。
注意:调用 watching
和 createNewData
的对象是 that
,因为 this
指向小程序页面实例,没有自定的这个方法。
做完上述改造,后续的 watch
和 computed
就简单多了。
侦听器 watch
MyPage.prototype.watching = function(data) {
var context = this.context
var oldData = context.data
// 开始生成新的数据
var watch = this.watch
if (watch) {
Object.keys(watch).forEach(function (k) {
// 如果新的 data 中属性被侦听,执行侦听函数
if (k in data) {
var newValue = data[k]
var oldValue = oldData[k]
watch[k].apply(context,[
newValue,oldValue
])
}
})
}
}
复制代码
简易的侦听器就写好了,通过 setData
触发自定的 watch 中的侦听函数。
计算器 computed
MyPage.prototype.getComputedData = function(data) {
var context = this.context
var computed = this.computed
var computedData
if (computed) {
computedData = computed.call(context,data)
}
return computedData
}
复制代码
这样就得到了计算后的新生成的数据:computedData
。
总结
不断的通过备份、代理微信原有的方法,自主实现了简单的侦听器和计算器。当然这些代码只是为了方便分享提取出来了提供思路,实际业务中遇到情况复杂的多,代码量远远也不止这些。
传送门
- 小程序技能进阶回忆录 - 也许你并不需要小程序框架
- 小程序技能进阶回忆录 - 在缺少组件化的日子里
- 小程序技能进阶回忆录 - 如何自主实现数据侦听器和计算器
- 小程序技能进阶回忆录 - 如何自主实现拦截器(待发布)
- 小程序技能进阶回忆录 - globalData 的那些事儿(待发布)
- 小程序技能进阶回忆录 - 什么时候执行 onLoad(待发布)
- 小程序技能进阶回忆录 - 增强型的 wx.navigateBack(待发布)
广告时间
美团单车事业部(摩拜单车)诚招前端 / 小程序研发工程师,位置北京,有兴趣可以发简历到 zhangshibing@mobike.com )