React前端DOM常見(jiàn)Hook封裝示例下
引言
本文是深入淺出 ahooks 源碼系列文章的第十五篇,這個(gè)系列的目標(biāo)主要有以下幾點(diǎn):
- 加深對(duì) React hooks 的理解。
- 學(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫(kù)。
- 培養(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫(kù)是一個(gè)對(duì)源碼閱讀不錯(cuò)的選擇。
上文指路: React前端DOM常見(jiàn)Hook封裝示例上
本篇接著針對(duì)關(guān)于 DOM 的各個(gè) Hook 封裝進(jìn)行解讀。
useFullscreen
管理 DOM 全屏的 Hook。
該 hook 主要是依賴(lài) screenfull 這個(gè) npm 包進(jìn)行實(shí)現(xiàn)的。
選擇它的原因,估計(jì)有兩個(gè):
- 它的兼容性好,兼容各個(gè)瀏覽器的全屏 API。
- 簡(jiǎn)單,包體積小。壓縮后只要 1.1 k。
大概介紹幾個(gè)它的 API。
- .request(element, options?)。使一個(gè)元素全屏顯示。默認(rèn)元素是
<html>
- .exit()。退出全屏。
- .toggle(element, options?)。假如目前是全屏,則退出,否則進(jìn)入全屏。
- .on(event, function)。添加一個(gè)監(jiān)聽(tīng)器,用于當(dāng)瀏覽器切換到全屏或切換出全屏或出現(xiàn)錯(cuò)誤時(shí)。event 支持 'change' 或者 'error'。另外兩種寫(xiě)法:
.onchange(function)
和.onerror(function)
。 - .isFullscreen。判斷是否是全屏。
- .isEnabled。判斷當(dāng)前環(huán)境是否支持全屏。
來(lái)看該 hook 的封裝:
首先是 onChange 事件中,判斷是否是全屏,從而觸發(fā)進(jìn)入全屏的函數(shù)或者退出全屏的函數(shù)。 當(dāng)退出全屏的時(shí)候,卸載 change
事件。
const { onExit, onEnter } = options || {}; // 退出全屏觸發(fā) const onExitRef = useLatest(onExit); // 全屏觸發(fā) 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); } };
手動(dòng)進(jìn)入全屏函數(shù),支持傳入 ref 設(shè)置需要全屏的元素。并通過(guò) screenfull.request
進(jìn)行設(shè)置,并監(jiān)聽(tīng) change 事件。
// 進(jìn)入全屏 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); } } };
退出全屏方法,調(diào)用 screenfull.exit()
。
// 退出全屏 const exitFullscreen = () => { if (!state) { return; } if (screenfull.isEnabled) { screenfull.exit(); } };
最后通過(guò) toggleFullscreen,根據(jù)當(dāng)前狀態(tài),調(diào)用上面兩個(gè)方法,達(dá)到切換全屏狀態(tài)的效果。
useHover
監(jiān)聽(tīng) DOM 元素是否有鼠標(biāo)懸停。
主要實(shí)現(xiàn)原理是監(jiān)聽(tīng) mouseenter
觸發(fā) onEnter 事件,切換狀態(tài)為 true,監(jiān)聽(tīng) mouseleave
觸發(fā) onLeave 事件,切換狀態(tài)為 false。代碼簡(jiǎn)單,如下:
export default (target: BasicTarget, options?: Options): boolean => { const { onEnter, onLeave } = options || {}; const [state, { setTrue, setFalse }] = useBoolean(false); // 通過(guò)監(jiān)聽(tīng) mouseenter 判斷有鼠標(biāo)懸停 useEventListener( 'mouseenter', () => { onEnter?.(); setTrue(); }, { target, }, ); // mouseleave 沒(méi)有鼠標(biāo)懸停 useEventListener( 'mouseleave', () => { onLeave?.(); setFalse(); }, { target, }, ); return state; };
useDocumentVisibility
監(jiān)聽(tīng)頁(yè)面是否可見(jiàn)。
這個(gè) hook 主要使用了 Document.visibilityState 這個(gè) API。先簡(jiǎn)單看下這個(gè) API:
Document.visibilityState
(只讀屬性), 返回document的可見(jiàn)性, 即當(dāng)前可見(jiàn)元素的上下文環(huán)境。由此可以知道當(dāng)前文檔 (即為頁(yè)面) 是在背后, 或是不可見(jiàn)的隱藏的標(biāo)簽頁(yè),或者 (正在) 預(yù)渲染??捎玫闹等缦拢?/p>
- 'visible' : 此時(shí)頁(yè)面內(nèi)容至少是部分可見(jiàn). 即此頁(yè)面在前景標(biāo)簽頁(yè)中,并且窗口沒(méi)有最小化。
- 'hidden' : 此時(shí)頁(yè)面對(duì)用戶(hù)不可見(jiàn)。即文檔處于背景標(biāo)簽頁(yè)或者窗口處于最小化狀態(tài),或者操作系統(tǒng)正處于 '鎖屏狀態(tài)' 。
- 'prerender' : 頁(yè)面此時(shí)正在渲染中,因此是不可見(jiàn)的。文檔只能從此狀態(tài)開(kāi)始,永遠(yuǎn)不能從其他值變?yōu)榇藸顟B(tài)。
典型用法是防止當(dāng)頁(yè)面正在渲染時(shí)加載資源,或者當(dāng)頁(yè)面在背景中或窗口最小化時(shí)禁止某些活動(dòng)。
最后看這個(gè) hook 的實(shí)現(xiàn)就很簡(jiǎn)單了:
- 通過(guò) document.visibilityState 判斷是否可見(jiàn)。
- 通過(guò) visibilitychange 事件,更新結(jié)果。
const getVisibility = () => { if (!isBrowser) { return 'visible'; } // Document.visibilityState (只讀屬性), 返回document的可見(jiàn)性, 即當(dāng)前可見(jiàn)元素的上下文環(huán)境。 return document.visibilityState; }; function useDocumentVisibility(): VisibilityState { const [documentVisibility, setDocumentVisibility] = useState(() => getVisibility()); useEventListener( // 監(jiān)聽(tīng)該事件 'visibilitychange', () => { setDocumentVisibility(getVisibility()); }, { target: () => document, }, ); return documentVisibility; }
以上就是React前端DOM常見(jiàn)Hook封裝示例下的詳細(xì)內(nèi)容,更多關(guān)于React前端 DOM Hook 封裝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
教你快速搭建 React Native 開(kāi)發(fā)環(huán)境
這篇文章主要介紹了搭建 React Native 開(kāi)發(fā)環(huán)境的詳細(xì)過(guò)程,本文通過(guò)圖文指令給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08react實(shí)現(xiàn)組件狀態(tài)緩存的示例代碼
本文主要介紹了react實(shí)現(xiàn)組件狀態(tài)緩存的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02react-player實(shí)現(xiàn)視頻播放與自定義進(jìn)度條效果
本篇文章通過(guò)完整的代碼給大家介紹了react-player實(shí)現(xiàn)視頻播放與自定義進(jìn)度條效果,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2022-01-01如何使用Redux Toolkit簡(jiǎn)化Redux
redux-toolkit是目前redux官方推薦的編寫(xiě)redux邏輯的方法,針對(duì)redux的創(chuàng)建store繁瑣、樣板代碼太多、依賴(lài)外部庫(kù)等問(wèn)題進(jìn)行了優(yōu)化,官方總結(jié)了四個(gè)特點(diǎn)是簡(jiǎn)易的/有想法的/強(qiáng)勁的/高效的,總結(jié)來(lái)看,就是更加的方便簡(jiǎn)單了2022-12-12React?Native?中處理?Android?手機(jī)吞字的解決方案
這篇文章主要介紹了React?Native?中處理?Android?手機(jī)吞字的解決方案,作者在 React Native 0.67.4 環(huán)境下,編寫(xiě)了一個(gè)小 demo 來(lái)復(fù)現(xiàn)這個(gè)問(wèn)題,需要的朋友可以參考下2022-08-08