直接上代碼:
import { noop } from 'lodash';
const rawAddEventListener = window.addEventListener;
const rawRemoveEventListener = window.removeEventListener;
這裏先保存window的添加和移除監聽的函數。
export default function hijack() {
const listenerMap = new Map<string, EventListenerOrEventListenerObject[]>();
window.addEventListener = (
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions,
) => {
const listeners = listenerMap.get(type) || [];
listenerMap.set(type, [...listeners, listener]);
return rawAddEventListener.call(window, type, listener, options);
};
...
函數名很顯而易見的知道這個函數的功能,函數劫持(其實就是改寫函數,在執行的時候保留原本功能並加上我們想要的副作用)。
函數裏面聲明瞭listenerMap來保存監聽器,
並改寫了window.addEventListener.在執行原本功能的時候往listenerMap上加入當前監聽器。
window.removeEventListener = (
type: string,
listener: EventListenerOrEventListenerObject,
options?: boolean | AddEventListenerOptions,
) => {
const storedTypeListeners = listenerMap.get(type);
if (storedTypeListeners && storedTypeListeners.length && storedTypeListeners.indexOf(listener) !== -1) {
storedTypeListeners.splice(storedTypeListeners.indexOf(listener), 1);
}
return rawRemoveEventListener.call(window, type, listener, options);
};
這裏改寫了removeEventListener並且在listenerMap上刪除原本的回調函數。
return function free() {
listenerMap.forEach((listeners, type) =>
[...listeners].forEach(listener => window.removeEventListener(type, listener)),
);
window.addEventListener = rawAddEventListener;
window.removeEventListener = rawRemoveEventListener;
return noop;
};
}
最後該函數返回一個重置window事件監聽功能的函數。
qiankun git鏈接 : https://github.com/umijs/qiankun