前言
在iOS开发中,有一个很好用的观察者模式
类NotificationCenter
,能很好的解决一对多,"一"发送通知,"多"接收通知的需求。
微信小程序中,页面与页面的通讯官方有提供一个叫EventChannel
的对象,用法如下:
wx.navigateTo({
url: 'test?id=1',
events: {
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
acceptDataFromOpenedPage: function(data) {
console.log(data)
},
someEvent: function(data) {
console.log(data)
}
...
},
success: function(res) {
// 通过eventChannel向被打开页面传送数据
res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
}
})
//test.js
Page({
onLoad: function(option){
console.log(option.query)
const eventChannel = this.getOpenerEventChannel()
eventChannel.emit('acceptDataFromOpenedPage', {data: 'test'});
eventChannel.emit('someEvent', {data: 'test'});
// 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
eventChannel.on('acceptDataFromOpenerPage', function(data) {
console.log(data)
})
}
})
EventChannel
能很好的解决上级页面和下级页面的数据交互,但是中间存在跨级或者页面之间不存在跳转层级关系时,EventChannel
就办不到了。
自己动手丰衣足食
因为开发微信小程序,所以接触了js这门语言。虽然是js小白,但是还是决定根据观察者设计模式来撸一个类似iOS开发中用到的通知库。
notify.js
1、引入
在需要用到的文件中引入
const notify = require('../../...your file path.../notify');
2. 注册通知方法
/**
- 添加通知监听
- @param {string} name 通知名
- @param {function} callback 通知回调
- @return {number} 通知唯一标识, 移除通知时会用到
*/
addNotify: function(name, callback)
以注册登录成功的通知为例:
this.notifyId = notify.addNotify('login_success' , (info)=>{
// your code
})
3.移除通知
/**
- 移除通知监听
- @param {string} name 通知名
- @param {number} index 通知唯一标识,调用addNotify函数时返回的
*/
removeNotify: function(name, index)
notify.removeNotify('login_success', this.notifyId)
4.发送通知
/**
- 触发通知
- @param {string} name 通知名
- @param {any} data 通知时携带的数据
*/
postNotify: function(name, data={})
notify.postNotify('login_success',{
username: '张三',
age: 18
})
notify.js 源码如下:
// 记录通知的对象
let manager = {}
// manager中的数组是否正在遍历中
let isForEach = false
// 等待移除通知的队列
let deleteArr = []
// 自增id
let notify_id = -1
/**
* 添加移除通知数据
* @param {string} name 通知名
* @param {number} index 对应的标识,详见 add 函数
*/
function addDeleteNotify(name, index) {
if (!manager[name]) {return}
deleteArr.push({name: name, index: index})
}
/**
* 移除通知
* @param {object} obj {name: '通知名', index: '对应标识'}
*/
function remove(obj) {
let notify = manager[obj.name]
if (!notify) {
return;
}
let keyStr = `${obj.index}`
if (notify[keyStr]) {
delete notify[keyStr]
}
manager[obj.name] = notify
}
/**
* 添加通知监听
* @param {string} name 通知名
* @param {function} callback 通知回调
* @return {number} 通知唯一标识, 移除通知时会用到
*/
function add(name, callback) {
if (!callback) {
return -1
}
let notify = manager[name] || {}
notify_id += 1
notify[`${notify_id}`] = callback
manager[name] = notify
return notify_id
}
/**
* 初始化方法,其实就是给自己添加一个删除通知的监听
*/
function init() {
add('cw_notify_delete', () => {
deleteArr.forEach(obj => {
remove(obj)
})
deleteArr = []
})
}
module.exports = {
/**
* 添加通知监听
* @param {string} name 通知名
* @param {function} callback 通知回调
* @return {number} 通知唯一标识, 移除通知时会用到
*/
addNotify: function(name, callback) {
if (!manager['cw_notify_delete']) {
// 没有初始化过,初始化一下
init()
}
return add(name, callback)
},
/**
* 移除通知监听
* @param {string} name 通知名
* @param {number} index 通知唯一标识,调用addNotify函数时返回的
*/
removeNotify: function(name, index) {
if (isForEach) {
// 正在遍历,添加到移除等待队列中
addDeleteNotify(name, index)
}else {
// 未遍历,直接移除
remove({name: name, index: index})
}
},
/**
* 触发通知
* @param {string} name 通知名
* @param {any} data 通知时携带的数据
*/
postNotify: function(name, data={}) {
let notify = manager[name]
if (!notify) {return;}
isForEach = true
let func = '', key = ''
let keys = Object.keys(notify)
for (let idx in keys) {
key = keys[idx]; func = notify[key]
if (Object.prototype.toString.call(func) == '[object Function]') {
func(data)
}
}
isForEach = false
if (name != 'cw_notify_delete') {
this.postNotify('cw_notify_delete')
}
}
}