React前端DOM常見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常見Hook封裝示例上
本篇接著針對(duì)關(guān)于 DOM 的各個(gè) Hook 封裝進(jìn)行解讀。
useFullscreen
管理 DOM 全屏的 Hook。
該 hook 主要是依賴 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)聽器,用于當(dāng)瀏覽器切換到全屏或切換出全屏或出現(xiàn)錯(cuò)誤時(shí)。event 支持 'change' 或者 'error'。另外兩種寫法:
.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)聽 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)聽 DOM 元素是否有鼠標(biāo)懸停。
主要實(shí)現(xiàn)原理是監(jiān)聽 mouseenter 觸發(fā) onEnter 事件,切換狀態(tài)為 true,監(jiān)聽 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)聽 mouseenter 判斷有鼠標(biāo)懸停
useEventListener(
'mouseenter',
() => {
onEnter?.();
setTrue();
},
{
target,
},
);
// mouseleave 沒(méi)有鼠標(biāo)懸停
useEventListener(
'mouseleave',
() => {
onLeave?.();
setFalse();
},
{
target,
},
);
return state;
};
useDocumentVisibility
監(jiān)聽頁(yè)面是否可見。
這個(gè) hook 主要使用了 Document.visibilityState 這個(gè) API。先簡(jiǎn)單看下這個(gè) API:
Document.visibilityState (只讀屬性), 返回document的可見性, 即當(dāng)前可見元素的上下文環(huán)境。由此可以知道當(dāng)前文檔 (即為頁(yè)面) 是在背后, 或是不可見的隱藏的標(biāo)簽頁(yè),或者 (正在) 預(yù)渲染。可用的值如下:
- 'visible' : 此時(shí)頁(yè)面內(nèi)容至少是部分可見. 即此頁(yè)面在前景標(biāo)簽頁(yè)中,并且窗口沒(méi)有最小化。
- 'hidden' : 此時(shí)頁(yè)面對(duì)用戶不可見。即文檔處于背景標(biāo)簽頁(yè)或者窗口處于最小化狀態(tài),或者操作系統(tǒng)正處于 '鎖屏狀態(tài)' 。
- 'prerender' : 頁(yè)面此時(shí)正在渲染中,因此是不可見的。文檔只能從此狀態(tà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 判斷是否可見。
- 通過(guò) visibilitychange 事件,更新結(jié)果。
const getVisibility = () => {
if (!isBrowser) {
return 'visible';
}
// Document.visibilityState (只讀屬性), 返回document的可見性, 即當(dāng)前可見元素的上下文環(huán)境。
return document.visibilityState;
};
function useDocumentVisibility(): VisibilityState {
const [documentVisibility, setDocumentVisibility] = useState(() => getVisibility());
useEventListener(
// 監(jiān)聽該事件
'visibilitychange',
() => {
setDocumentVisibility(getVisibility());
},
{
target: () => document,
},
);
return documentVisibility;
}以上就是React前端DOM常見Hook封裝示例下的詳細(xì)內(nèi)容,更多關(guān)于React前端 DOM Hook 封裝的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
antd4里table滾動(dòng)的實(shí)現(xiàn)
本文主要介紹了antd4里table滾動(dòng)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
react循環(huán)數(shù)據(jù)(列表)的實(shí)現(xiàn)
這篇文章主要介紹了react循環(huán)數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
React Native中導(dǎo)航組件react-navigation跨tab路由處理詳解
這篇文章主要給大家介紹了關(guān)于React Native中導(dǎo)航組件react-navigation跨tab路由處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10
React Hook父組件如何獲取子組件的數(shù)據(jù)/函數(shù)
這篇文章主要介紹了React Hook父組件如何獲取子組件的數(shù)據(jù)/函數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
解決React報(bào)錯(cuò)The?tag?is?unrecognized?in?this?browser
這篇文章主要為大家介紹了解決React報(bào)錯(cuò)The?tag?is?unrecognized?in?this?browser示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
React渲染機(jī)制及相關(guān)優(yōu)化方案
這篇文章主要介紹了react中的渲染機(jī)制以及相關(guān)的優(yōu)化方案,內(nèi)容包括react渲染步驟、concurrent機(jī)制以及產(chǎn)生作用的機(jī)會(huì),簡(jiǎn)單模擬實(shí)現(xiàn) concurrent mode,基于作業(yè)調(diào)度優(yōu)先級(jí)的思路進(jìn)行項(xiàng)目?jī)?yōu)化的兩個(gè)hooks,感興趣的小伙伴跟著小編一起來(lái)看看吧2023-07-07
react-native使用leanclound消息推送的方法
這篇文章主要介紹了react-native使用leanclound消息推送的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08

