为微信小程序增加通知机制
当有多个页面需要监听某个状态(如:登录状态),当状态发生改变时,需要及时通知到每个监听者(页面),这就是通知机制。
源码
新建一个 NotificationCenter.js
文件,内容如下:
/**
* @variable 记录所有注册的通知
*
* key为通知的名称,value为监听该通知的对象数组
*/
let _observerTables = {};
const NC_NAME_KEY = 'NC_NAME_KEY';
const NC_OBSERVER_KEY = 'NC_OBSERVER_KEY';
const NS_CALLBACK_KEY = 'NS_CALLBACK_KEY';
/**
* @class 通知中心管理类
*
* 添加/移除是成对出现的,需要自行移除观察者对象
* 否则将会导致观察者对象不被释放,造成内存泄漏
*
* 如果页面只需要在当前展示时进行监听,则在`onShow()`中添加,在`onHide()`中移除
* 如果页面需要在整个生命周期内进行监听,则在`onLoad()`中添加,在`onUnload()`中移除
*/
class NotificationCenter {
/**
* @method 添加一个观察者对象
*
* @param observer {Object} 观察者(Page对象)
* @param name {String} 通知的名称
* @param callback {String/Function} 回调(接收一个Object类型的参数,如果为字符串则确保observer对象实现了该方法)
*/
static addObserver(observer, name, callback) {
if (typeof observer !== 'object' || observer === null) {
throw new Error(`${observer} is not a Page object.`);
}
if (typeof name !== 'string' || !name.length) {
throw new Error(`${name} is not a string or is empty.`);
}
if (typeof callback === 'string') {
if (typeof Reflect.get(observer, callback) !== 'function') {
throw new Error(`${observer} not implemented ${callback} method.`);
}
} else if (typeof callback !== 'function') {
throw new Error(`${callback} is not a function.`);
}
let observers = Reflect.get(_observerTables, name) || [];
observers.push({
NC_NAME_KEY: name,
NC_OBSERVER_KEY: observer,
NS_CALLBACK_KEY: callback
});
Reflect.set(_observerTables, name, observers);
}
/**
* @method 移除观察者对象
*
* @param observer {Object} 观察者(Page对象)
* @param name {String} 通知的名称, 如果未指定则会移除`observer`注册的所有通知
*/
static removeObserver(observer, name = null) {
const removeObserverBlock = (o, k) => {
let obs = Reflect.get(_observerTables, k).filter(element => {
return (Reflect.get(element, NC_OBSERVER_KEY) != o);
});
if (obs.length) {
Reflect.set(_observerTables, k, obs);
} else {
Reflect.deleteProperty(_observerTables, k);
}
};
if (typeof name === 'string' && name.length) {
// 移除指定通知名称的观察者
if (!Reflect.has(_observerTables, name)) {
return;
}
removeObserverBlock(observer, name);
} else {
// 未指定通知名称, 移除 observer 监听的所有通知事件
for (let key in _observerTables) {
removeObserverBlock(observer, key);
}
}
}
/**
* @method 发送一个通知
*
* @param name {String} 通知的名称
* @param userInfo {Object} 需要传递给观察者的数据,默认为`null`
*/
static postNotificationName(name, userInfo = null) {
if (typeof name !== 'string' || !name.length) {
throw new Error('`name` is illegal parameter.');
}
if (!Reflect.has(_observerTables, name)) {
return;
}
const notification = { name: name, userInfo: userInfo };
const obs = Reflect.get(_observerTables, name);
obs.forEach((o) => {
let observer = Reflect.get(o, NC_OBSERVER_KEY);
let callback = Reflect.get(o, NS_CALLBACK_KEY);
let func = (typeof callback === 'function') ? callback : Reflect.get(observer, callback);
Reflect.apply(func, observer, [notification]);
});
}
}
module.exports = NotificationCenter;
使用示例
页面A监听某个通知
1、导入文件
const NotificationCenter = require('NotificationCenter.js');
2、当页面加载完毕时注册通知(onLoad方法中调用)
page 对象必须实现 notificationCallback 方法
NotificationCenter.addObserver(this, 'NOTIFICATION_NAME', 'notificationCallback');
匿名函数方式回调
NotificationCenter.addObserver(this, 'NOTIFICATION_NAME', (res) => { console.log(res); });
两种注册方式,选择你喜欢的一种即可。
3、当页面卸载时移除通知(onUnload方法中调用)
NotificationCenter.removeObserver(this, 'NOTIFICATION_NAME');
页面B中发出通知
4、发出通知
NotificationCenter.postNotificationName('NOTIFICATION_NAME', {'userInfo' : null});
注:
1、2和3是成对出现的,添加了注册就要记得移除
2、可以根据实际需求在 onLoad/onUnload、onShow/onHide 中进行添加/移除操作