小程序对某个对象实现深度监听
场景
- 有一个与页面实例不关联的外部对象,当其某个属性改变时,需要页面做出反应,也就是页面需要监听它
问题
- 肯定直接想到计算属性,但是小程序不自带,然后用wx-computed等插件,发现都有缺陷,只能对页面实例内部data的属性进行监听
- 然而就算把这个外部对象声明到page的data里,但由于对象属性的改变不是响应式的,这在vue里还能通过$set来解决,但是没有$set就只能想办法自己实现对该外部对象的深度监听
解决
-
在app.js中定义全局的监听函数
App({ onLaunch: function () { console.log('app running') }, // 设置监听器 // ctx表示上下文,aim表示监听的目标对象,一般情况非深度监听没有aim参数,而是直接对ctx监听 // keys表示监听的目标对象的目标属性,其值是一个函数,也就是监听到其变化后触发的回调,然后call ctx给回调 watch: function (ctx, aim, keys) { Object.keys(keys).forEach(key => { this.observer(aim, key, aim[key], function (value) { keys[key].call(ctx, value) }) }) }, // 监听属性,并执行监听函数 observer: function (data, key, val, callback) { Object.defineProperty(data, key, { configurable: true, enumerable: true, get: function () { return val }, // 重写set函数,就能在其属性改变时触发回调 set: function (newVal) { if (newVal === val) return callback && callback(newVal) val = newVal }, }) } })
-
然后在需要使用的page实例中引入
const app = getApp() // 这里的上下文直接传this,Obj就是需要监听的外部对象,监听的属性是objProperty,然后页面在回调里做出响应 app.watch(this, Obj, { objProperty: function (newVal) { if (newVal) { this.setData({ pageVar: newVal }) } } })
-
但是这里笔者也没有实现完全深度监听,比如上面监听的objProperty如果又是一个对象,就又出现了同样的问题,objProperty的某个属性改变不是响应式的,这时候就要在watch的定义里,对aim[key]判断是否是对象,如果是,需要递归一下,就能完全深度监听了