再续那些关于DOM的常见Hook封装

本篇接着针对关于 DOM 的再续装各个 Hook 封装进行解读。useFullscreen

管理 DOM 全屏的那关 Hook。

再续那些关于DOM的常见Hook封装

该 hook 主要是再续装依赖 screenfull[1] 这个 npm 包进行实现的。

再续那些关于DOM的常见Hook封装

选择它的那关原因,估计有两个:

再续那些关于DOM的常见Hook封装

它的再续装兼容性好,兼容各个浏览器的那关全屏 API。简单,再续装包体积小。那关压缩后只要 1.1 k。再续装

大概介绍几个它的那关 API。

.request(element,再续装 options?)。使一个元素全屏显示。那关默认元素是再续装<html>.exit()。退出全屏。那关.toggle(element,再续装 options?)。假如目前是全屏,则退出,否则进入全屏。.on(event, function)。添加一个监听器,用于当浏览器切换到全屏或切换出全屏或出现错误时。event 支持 change 或者 error。另外两种写法:.onchange(function)​ 和.onerror(function)。.isFullscreen。源码库判断是否是全屏。.isEnabled。判断当前环境是否支持全屏。

来看该 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();

}

};​useHover

监听 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;

};useDocumentVisibility

监听页面是否可见。

这个 hook 主要使用了 Document.visibilityState 这个 API。先简单看下这个 API:

Document.visibilityState (只读属性), 返回document的可见性, 即当前可见元素的上下文环境。由此可以知道当前文档 (即为页面) 是在背后, 或是不可见的隐藏的标签页,或者 (正在) 预渲染。可用的值如下:

visible : 此时页面内容至少是部分可见. 即此页面在前景标签页中,并且窗口没有最小化。hidden : 此时页面对用户不可见。即文档处于背景标签页或者窗口处于最小化状态,或者操作系统正处于 锁屏状态 。prerender : 页面此时正在渲染中,因此是不可见的。文档只能从此状态开始,永远不能从其他值变为此状态。

典型用法是香港云服务器防止当页面正在渲染时加载资源,或者当页面在背景中或窗口最小化时禁止某些活动。

最后看这个 hook 的实现就很简单了:

通过 document.visibilityState 判断是否可见。通过 visibilitychange 事件,更新结果。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;

}参考资料

[1]screenfull: https://www.npmjs.com/package/screenfull

滇ICP备2023000592号-31