前言
設計模式、釋出、訂閱、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