实现小程序中的数据侦听
最近接触的taro项目中使用了VX,因此记录一下了解到的内容,原文
在小程序项目中, 我们的通常会使用到使用到一个全局对象作为各个页面通用的数据存储容器, 将它绑定到app对象后, 就能在每一个页面都自由的操纵这个对象. 然而在实践中, 由于这个对象及其属性不具备响应式条件, 它不能直接参与业务逻辑的编写, 能力仅仅局限于数据储存. 若是在VueJS项目中, 我们可能经常使用到Vue.$watch去侦听某个数据是否发生变化, 小程序却缺乏这种能力.
在这篇文章中, 我将用150行代码, 手把手带你打造一个小程序也可以使用的侦听器(下简称VX):
// 一个快速赋值的语法糖函数, 可以创建结构为 { value: a { b: { val: ''} } } 的对象
vx.set('value.a.d', { val: '' })
// 对某个属性进行侦听, 如果发生改变, 则执行相应函数(可多次watch以执行多个函数)
vx.watch('value.a.d.val', newVal => {
console.log(`val改变为 : `, newVal)
})
value.a.d.val = 3 // val改编为 : 3
使用VX侦听器, 我们可以更加方便的管理各个页面的状态. 同时, 我们凭借watch语法, 可以更优雅地编写业务逻辑.
在全局对象中, 我们不一定要对每一个属性都进行侦听, 所以VX主要的功能就是通过set去设置某个具体属性的setter/getter, 同时通过watch向添加该属性添加需要订阅的回调函数.
设置响应式属性
defineProperty
可能是因为接触DefineProperty要比接触Proxy早一些的缘故, 代码使用了前者进行响应式的实现, Object.defineProperty方法会直接在一个对象上定义一个新属性, 这里快速过一遍defineProperty
具体配置:
// @param obj 要在其上定义属性的对象
// @param key 要定义或修改的属性的名称
Object.defineProperty(obj, key, {
// 该属性是否能被枚举
enumerable: true,
// 该属性能否被删除
configurable: true,
// 访问该属性则会执行此方法
get: () => {
return val
},
// 修改该属性时会执行此方法
set: newVal => {
val = newVal
},
// value & writeble 不能和 getter/setter 同时出现
})
通过watch添加订阅
首先一点, 我们创建一个侦听器类, 用于封装我们侦听所用到的所有方法, 它包含了我们想要的全局对象以及操作它的方法(如watch,set):
class VX {
constructor () {
this.store = Object.create(null)
}
watch (key, fn, obj = this.store) {}
set (key, val, options = {}, obj = this.store) {}
}
const vx = new VX()
业务场景应用
小程序跨页面刷新数据
我们经常碰到在小程序中由A页面跳转到B页面, 如果B页面进行了一些操作, 希望A页面自动刷新数据的情况. 但是由于A页面跳转到B页面不同(也许是redirect,也许是navigate), 处理方法也不尽相同.
使用navigate方式跳转后, A页面不会被注销, 所以我们一般会通过全局对象去贮存A页面实例(也就是A页面的this对象), 然后在B页面直接调用相应的方法(如A.refreshList())进行刷新操作.
引入VX后, 我们可以在`onload`生命周期直接调用watch方法添加订阅:
// app.js
import VX from '@/utils/suites/vx'
const vx = new VX()
app.vx = vx
app.store = vx.store
app.vx.set('userType', '商户')
// page a
onLoad () {
app.vx.watch('userType', userType => {
if (userType === '商户') {
// ...
} else if (userType === '管理员') {
// ...
}
}, {
immediate: true
})
}
// page b
switchUserType () {
app.store.userType = '管理员'
}
在这篇文章中, 我们通过对defineProperty进行封装, 实现了一个简单的对象属性侦听器的功能, 以弥补小程序所没有的$watch能力. 在此基础上, 各位可以再对VX进行扩展, 更方便地去书写业务代码.
完整代码Github直达
1