本文是深入淺出 ahooks 原始碼系列文章的第十五篇,該系列已整理成檔案-地址。覺得還不錯,給個 star 支援一下哈,Thanks。
本篇接著針對關於 DOM 的各個 Hook 封裝進行解讀。
管理 DOM 全螢幕的 Hook。
該 hook 主要是依賴 screenfull 這個 npm 包進行實現的。
選擇它的原因,估計有兩個:
大概介紹幾個它的 API。
<html>
.onchange(function)
和 .onerror(function)
。來看該 hook 的封裝:
首先是 onChange 事件中,判斷是否是全螢幕,從而觸發進入全螢幕的函數或者退出全螢幕的函數。
當退出全螢幕的時候,解除安裝 change
事件。
const { onExit, onEnter } = options || {};
// 退出全螢幕觸發
const onExitRef = useLatest(onExit);
// 全螢幕觸發
const onEnterRef = useLatest(onEnter);
const [state, setState] = useState(false);
const onChange = () => {
if (screenfull.isEnabled) {
const { isFullscreen } = screenfull;
if (isFullscreen) {
onEnterRef.current?.();
} else {
screenfull.off('change', onChange);
onExitRef.current?.();
}
setState(isFullscreen);
}
};
手動進入全螢幕函數,支援傳入 ref 設定需要全螢幕的元素。並通過 screenfull.request
進行設定,並監聽 change 事件。
// 進入全螢幕
const enterFullscreen = () => {
const el = getTargetElement(target);
if (!el) {
return;
}
if (screenfull.isEnabled) {
try {
screenfull.request(el);
screenfull.on('change', onChange);
} catch (error) {
console.error(error);
}
}
};
退出全螢幕方法,呼叫 screenfull.exit()
。
// 退出全螢幕
const exitFullscreen = () => {
if (!state) {
return;
}
if (screenfull.isEnabled) {
screenfull.exit();
}
};
最後通過 toggleFullscreen,根據當前狀態,呼叫上面兩個方法,達到切換全螢幕狀態的效果。
// 切換模式
const toggleFullscreen = () => {
if (state) {
exitFullscreen();
} else {
enterFullscreen();
}
};
監聽 DOM 元素是否有滑鼠懸停。
主要實現原理是監聽 mouseenter
觸發 onEnter 事件,切換狀態為 true,監聽 mouseleave
觸發 onLeave 事件,切換狀態為 false。程式碼簡單,如下:
export default (target: BasicTarget, options?: Options): boolean => {
const { onEnter, onLeave } = options || {};
const [state, { setTrue, setFalse }] = useBoolean(false);
// 通過監聽 mouseenter 判斷有滑鼠懸停
useEventListener(
'mouseenter',
() => {
onEnter?.();
setTrue();
},
{
target,
},
);
// mouseleave 沒有滑鼠懸停
useEventListener(
'mouseleave',
() => {
onLeave?.();
setFalse();
},
{
target,
},
);
return state;
};
監聽頁面是否可見。
這個 hook 主要使用了 Document.visibilityState 這個 API。先簡單看下這個 API:
Document.visibilityState
(唯讀屬性), 返回document的可見性, 即當前可見元素的上下文環境。由此可以知道當前檔案 (即為頁面) 是在背後, 或是不可見的隱藏的分頁,或者 (正在) 預渲染。可用的值如下:
典型用法是防止當頁面正在渲染時載入資源,或者當頁面在背景中或視窗最小化時禁止某些活動。
最後看這個 hook 的實現就很簡單了:
const getVisibility = () => {
if (!isBrowser) {
return 'visible';
}
// Document.visibilityState (唯讀屬性), 返回document的可見性, 即當前可見元素的上下文環境。
return document.visibilityState;
};
function useDocumentVisibility(): VisibilityState {
const [documentVisibility, setDocumentVisibility] = useState(() => getVisibility());
useEventListener(
// 監聽該事件
'visibilitychange',
() => {
setDocumentVisibility(getVisibility());
},
{
target: () => document,
},
);
return documentVisibility;
}
本文已收錄到個人部落格中,歡迎關注~