小程序app.globalData属性值改变时其它页面的引用响应更新
发布于 3 年前 作者 tdeng 4180 次浏览 来自 分享

前提说明

小程序app.js的globalData中定义了userInfo属性,并且在首页和我的tab中引用了,当在其它页面更新userInfo后,在首页和我的中引用的userInfo未更新。

解决思路

利用发布-订阅的设计模式,app.js中的userInfo用Object.defineProperty实现数据劫持,当监听到userInfo值改变时,通知每个订阅者。在首页和我的页面调用app.js中的订阅方法,将更新数据的方法追加到userInfo的订阅者列表中。

实现代码

// 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,
        });
    });
},

 

遇到的问题

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

回到顶部