前言
在iOS開發(fā)中,有一個很好用的觀察者模式
類NotificationCenter
宇姚,能很好的解決一對多匈庭,"一"發(fā)送通知,"多"接收通知的需求浑劳。
微信小程序中阱持,頁面與頁面的通訊官方有提供一個叫EventChannel
的對象,用法如下:
wx.navigateTo({
url: 'test?id=1',
events: {
// 為指定事件添加一個監(jiān)聽器魔熏,獲取被打開頁面?zhèn)魉偷疆?dāng)前頁面的數(shù)據(jù)
acceptDataFromOpenedPage: function(data) {
console.log(data)
},
someEvent: function(data) {
console.log(data)
}
...
},
success: function(res) {
// 通過eventChannel向被打開頁面?zhèn)魉蛿?shù)據(jù)
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'});
// 監(jiān)聽acceptDataFromOpenerPage事件衷咽,獲取上一頁面通過eventChannel傳送到當(dāng)前頁面的數(shù)據(jù)
eventChannel.on('acceptDataFromOpenerPage', function(data) {
console.log(data)
})
}
})
EventChannel
能很好的解決上級頁面和下級頁面的數(shù)據(jù)交互,但是中間存在跨級或者頁面之間不存在跳轉(zhuǎn)層級關(guān)系時蒜绽,EventChannel
就辦不到了镶骗。
自己動手豐衣足食
因為開發(fā)微信小程序,所以接觸了js這門語言躲雅。雖然是js小白鼎姊,但是還是決定根據(jù)觀察者設(shè)計模式來擼一個類似iOS開發(fā)中用到的通知庫。
notify.js
1、引入
在需要用到的文件中引入
const notify = require('../../...your file path.../notify');
2. 注冊通知方法
/**
- 添加通知監(jiān)聽
- @param {string} name 通知名
- @param {function} callback 通知回調(diào)
- @return {number} 通知唯一標(biāo)識, 移除通知時會用到
*/
addNotify: function(name, callback)
以注冊登錄成功的通知為例:
this.notifyId = notify.addNotify('login_success' , (info)=>{
// your code
})
3.移除通知
/**
- 移除通知監(jiān)聽
- @param {string} name 通知名
- @param {number} index 通知唯一標(biāo)識此蜈,調(diào)用addNotify函數(shù)時返回的
*/
removeNotify: function(name, index)
notify.removeNotify('login_success', this.notifyId)
4.發(fā)送通知
/**
- 觸發(fā)通知
- @param {string} name 通知名
- @param {any} data 通知時攜帶的數(shù)據(jù)
*/
postNotify: function(name, data={})
notify.postNotify('login_success',{
username: '張三',
age: 18
})
notify.js 源碼如下:
// 記錄通知的對象
let manager = {}
// manager中的數(shù)組是否正在遍歷中
let isForEach = false
// 等待移除通知的隊列
let deleteArr = []
// 自增id
let notify_id = -1
/**
* 添加移除通知數(shù)據(jù)
* @param {string} name 通知名
* @param {number} index 對應(yīng)的標(biāo)識即横,詳見 add 函數(shù)
*/
function addDeleteNotify(name, index) {
if (!manager[name]) {return}
deleteArr.push({name: name, index: index})
}
/**
* 移除通知
* @param {object} obj {name: '通知名', index: '對應(yīng)標(biāo)識'}
*/
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
}
/**
* 添加通知監(jiān)聽
* @param {string} name 通知名
* @param {function} callback 通知回調(diào)
* @return {number} 通知唯一標(biāo)識, 移除通知時會用到
*/
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
}
/**
* 初始化方法,其實就是給自己添加一個刪除通知的監(jiān)聽
*/
function init() {
add('cw_notify_delete', () => {
deleteArr.forEach(obj => {
remove(obj)
})
deleteArr = []
})
}
module.exports = {
/**
* 添加通知監(jiān)聽
* @param {string} name 通知名
* @param {function} callback 通知回調(diào)
* @return {number} 通知唯一標(biāo)識, 移除通知時會用到
*/
addNotify: function(name, callback) {
if (!manager['cw_notify_delete']) {
// 沒有初始化過裆赵,初始化一下
init()
}
return add(name, callback)
},
/**
* 移除通知監(jiān)聽
* @param {string} name 通知名
* @param {number} index 通知唯一標(biāo)識东囚,調(diào)用addNotify函數(shù)時返回的
*/
removeNotify: function(name, index) {
if (isForEach) {
// 正在遍歷,添加到移除等待隊列中
addDeleteNotify(name, index)
}else {
// 未遍歷战授,直接移除
remove({name: name, index: index})
}
},
/**
* 觸發(fā)通知
* @param {string} name 通知名
* @param {any} data 通知時攜帶的數(shù)據(jù)
*/
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')
}
}
}