三種風格,第一種是監(jiān)聽器本身作為標識,第二種是使用額外的一個 id(數(shù)字或字符串)來代表監(jiān)聽器,第三種是在調用監(jiān)聽方法時,直接返回一個可以取消監(jiān)聽的函數(shù)。

大家好,我是前端西瓜哥。
事件訂閱是模塊間解耦的常見方式。
比如相隔遙遠的兩個組件,可以通過一個訂閱,一個發(fā)布的方式,實現(xiàn)數(shù)據(jù)通信。
下面我們來看看事件訂閱的幾種設計風格。
監(jiān)聽器函數(shù)
第一種是 使用監(jiān)聽器函數(shù)本身作為標識符。
常見的場景有 DOM 事件的綁定:
const handler = () {
// do something
}
window.addEventListener('resize', handler); // 綁定事件
window.removeEventListener('resize', handler); // 取消事件
此外還有 Node.js 的 EventEmitter 類,很多支持監(jiān)聽事件的類都繼承了它。用法為:
import { EventEmitter } from "node:events";
const myEmitter = new EventEmitter();
const handler = () {
console.log("前端西瓜哥");
};
myEmitter.on("event", handler); // 綁定事件
myEmitter.emit("event"); // 打印了內容
myEmitter.off("event", handler); // 取消事件
myEmitter.emit("event"); // 無事發(fā)生
原理很簡單,就是維護一個映射表上,key 為事件名,value 為要順序執(zhí)行的監(jiān)聽器,大概這樣:
{
'resize': [handler1, handler2],
'click': [handler3, handler4]
}
一個監(jiān)聽器函數(shù)就是一個唯一的對象,通過它可以找出在對應事件下的位置,將其從列表中移除,就算是取消了事件綁定。
取消綁定邏輯大概為:
const index = map[eventName].indexOf(handler);
if (index !== -1) {
map[eventName].splice(index, 1);
}
訂閱 id
通過一個 id 來代表綁定的監(jiān)聽器。
經典場景為 setTimeout:
const timeoutId = setTimeout(() {
// ...
}, 1000); // 訂閱
clearTimeout(timeoutId); // 取消
實現(xiàn)原來基本類似前一種方式,只是改為用 id 來作為標識。
{
[eventName]: [
{id: 1, hander: handler1},
{id: 2, hander: handler2},
]
}
返回封裝好的取消綁定方法
上面兩種寫法,都需要一個變量額外保存標識,然后再使用事件訂閱對象專門的取消訂閱函數(shù),難免有點繁瑣。
我們對第一種風格,可以做一個封裝:
const bindEvent = (target, eventName, handler) => {
target.addEventListener('resize', handler); // 綁定
return () {
target.removeEventListener('resize', handler); // 取消
}
}
const unBindEvent = bindEvent(window, 'resize', handler); // 封裝的綁定
unBindEvent(); // 封裝的取消
這種寫法直接調用返回的函數(shù)即可解綁,不需要保存 id 和一個專門的取消訂閱函數(shù),代碼更簡潔。
常見場景是 React 的 useEffect:
const App = () {
useEffect(() {
const handler = () {
// ...
}
window.addEventListener('resize', handler); // 綁定事件
return () {
window.removeEventListener('resize', handler); // 取消事件
}
}, [])
}
結尾
三種風格,第一種是監(jiān)聽器本身作為標識,第二種是使用額外的一個 id(數(shù)字或字符串)來代表監(jiān)聽器,第三種是在調用監(jiān)聽方法時,直接返回一個可以取消監(jiān)聽的函數(shù)。