0%

JS 全局监听 globalData 的某个属性变化

问题

需要监听小程序的 globalData 的某个属性变化,当变化时,执行某个函数

除了 app.js 中要监听,其他页面也要监听。

解决

app.js 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
App({
onLaunch: function () {},
onShow: function () {},
onHide: function () {
// wx.stopLocationUpdate()
},
watch: function (key, method) {
var obj = this.globalData;
// 加个前缀生成隐藏变量,防止死循环发生
let ori = obj[key]; // obj[key] 这个不能放在 Object.defineProperty 里
if (ori) {
//处理已经声明的变量,绑定处理
method(ori);
}
Object.defineProperty(obj, key, {
configurable: true, // 属性是否可以被删除或者可否被重新定义特性
enumerable: true, // 是否可以被枚举,简单讲就是在使用Object.keys()时,是否能拿到键值
set: function (value) {
this['_' + key] = value;
console.log('是否会被执行2');
method(value);
},
get: function () {
// 在其他界面调用key值的时候,这里就会执行。
if (typeof this['_' + key] == 'undefined') {
if (ori) {
//这里读取数据的时候隐藏变量和 globalData设置不一样,所以要做同步处理
this['_' + key] = ori;
return ori;
} else {
return undefined;
}
} else {
return this['_' + key];
}
},
});
},
globalData: {
count: 0,
},
});

其他页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const app = getApp();
Page({
/**
* 页面的初始数据
*/
data: {
count: 0,
},
//
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
app.watch('count', (v) => {
that.setData({
count: v,
});
});
},
});

后记

分析一下下面的代码,和上面的代码想比,它有什么问题,为什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 监听全局变量变化
watch: function (variate, method) {
var obj = this.globalData;
let val = obj[variate];// 单独变量来存储原来的值
Object.defineProperty(obj, variate, {
configurable: false,
enumerable: true,
set: function (value) {
val = value;// 重新赋值
method(variate,value);// 执行回调方法
},
get: function () {
// 在其他界面调用getApp().globalData.variate的时候,这里就会执行。
return val; // 返回当前值
}
})
},

小心 Object.defineProperty 中的 set 方法死循环导致栈溢出。在 setobj[key] = value 时将会导致死循环,因为给属性赋值后,会再次调用 set 方法。解决的办法是利用闭包的原理,定义临时变量为 obj[key],在 set 方法中对临时变量赋值。或者在 obj 中声明一个变量的副本,set 中对变量副本赋值,get 中返回变量副本。

还有一段代码写的不错,可以参考一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// app.js
onLaunch: async function () {
this.initObserve();
},

// 监听globalData中属性变化
initObserve() {
const obj = this.globalData;
const keys = ['userInfo'];
keys.forEach(key => {
let value = obj[key];
obj[`${key}SubscriberList`] = [];
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set(newValue) {
obj[`${key}SubscriberList`].forEach(watch => {
watch(newValue);
});
value = newValue;
},
get() {
return value;
}
});
});
},

// 订阅globalData中某个属性变化
subscribe(key, watch) {
watch(this.globalData[key]);
this.globalData[`${key}SubscriberList`].push(watch);
},

// 首页和我的page页
onLoad() {
app.subscribe('userInfo', (userInfo) => {
this.setData({
userInfo,
});
});
},

参考文章