前言
设计模式、发布、订阅、Event、事件
分享一个开发中比较常用到的设计模式发布-订阅模式
也可以叫观察者模式
,在发布-订阅模式
中主要有两个角色:发布者 和 订阅者。
生活中最常用到的一个场景就是当你在QQ空间发布一条心情的时候所有你的QQ好友都会收到你的QQ动态,在这个例子中 你
就是 发布者
,而 QQ 好友
则会是订阅者。
const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
(this.hub[event] || []).forEach(handler => handler(data));
},
on(event, handler) {
if (!this.hub[event]) this.hub[event] = [];
this.hub[event].push(handler);
},
off(event, handler) {
const i = (this.hub[event] || []).findIndex(h => h === handler);
if (i > -1) this.hub[event].splice(i, 1);
}
});
代码分析
使用 Object.prototype.create
方法来快速创建了一个内部对象:
hub: Object.create(null)
使用 Array.prototype.forEach
来遍历监听事件对应的所有操作:
emit(event, data) {
(this.hub[event] || []).forEach(handler => handler(data));
}
使用 Array.prototype.push
来存储事件对应的操作:
on(event, handler) {
if (!this.hub[event]) this.hub[event] = [];
this.hub[event].push(handler);
}
使用 Array.prototype.findIndex
来查询事件对应的操作并使用 Array.prototype.splice
来去除操作:
off(event, handler) {
const i = (this.hub[event] || []).findIndex(h => h === handler);
if (i > -1) this.hub[event].splice(i, 1);
}
使用场景
当用户输入 表单数据
对 页面数据
和 data
进行同步更新,反之当 data
被其他操作修改时 对 页面数据
和 表单数据
进行同步更新,这样就简单的实现了一个类似 Vue
的数据双向绑定。
记得在项目开发过程中 大叔
在一个 jQuery 的前端项目中为了方便数据的变更和维护引入了 Vue
使得项目变得臃肿和复杂,如果使用 发布-订阅模式
则可以很方便的来实现这个操作而无需引入这么大的一个框架。
当单页面项目并不巨大,我们无需引入像 Redux
和 Vuex
这样的数据管理库,使用 发布-订阅模式
也可以很方便的管理组件之间的数据变更和依赖更新。
结构
<h2>用户数据</h2>
<div id="info">
<h3>
用户名:<span id="username"></span>
</h3>
<h3>
密码:<span id="password"></span>
</h3>
</div>
<h2>请输入用户数据</h2>
<div id="form">
<input type="text" name="username" oninput="hub.emit('oninput', 'username')" />
<input type="text" name="password" oninput="hub.emit('oninput', 'password')" />
<button type="button" onclick="hub.emit('submit')">确定</button>
<button type="button" onclick="hub.emit('resetFormData')">重置</button>
</div>
脚本
// 基础表单数据
let data = {
username: '',
password: '',
}
const hub = createEventHub()
// 监听表单输入事件
hub.on('oninput', (name) => {
const dom = document.querySelector(`[name="${name}"]`)
hub.emit('setFormData', { name, value: dom.value })
})
// 监听数据变更事件
hub.on('setFormData', ({ name, value }) => {
data[name] = value
})
// 监听数据变更事件
hub.on('setFormData', ({ name, value }) => {
const dom = document.querySelector(`#${name}`)
dom.innerHTML = value
})
// 监听数据变更事件
hub.on('setFormData', ({ name, value }) => {
const dom = document.querySelector(`[name="${name}"]`)
dom.value = value
})
// 监听页面数据提交事件
hub.on('submit', () => {
// ajax 发送数据请
// 这里用 setTimeout 来模拟 ajax 请求发送
setTimeout(() => {
alert('数据发送成功')
hub.emit('resetFormData')
}, 1000)
})
// 监听页面数据提交事件
hub.on('resetFormData', () => {
hub.emit('setFormData', { name: 'username', value: '' })
hub.emit('setFormData', { name: 'password', value: '' })
})
一起成长
在困惑的城市里总少不了并肩同行的 伙伴
让我们一起成长。
- 如果您想让更多人看到文章可以点个
点赞
。 - 如果您想激励小二可以到 Github 给个
小星星
。 - 如果您想与小二更多交流添加微信
m353839115
。
本文原稿来自 PushMeTop
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。