当前位置:网站首页>About the common Hook encapsulation of DOM (2)
About the common Hook encapsulation of DOM (2)
2022-08-09 19:44:00 【Ink fragrance ^_^】
本文是深入浅出 ahooks 源码系列文章的第十五篇,这个系列的目标主要有以下几点:
加深对 React hooks 的理解.
学习如何抽象自定义 hooks.构建属于自己的 React hooks 工具库.
培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择.
本篇接着针对关于 DOM 的各个 Hook 封装进行解读.
useFullscreen
管理 DOM 全屏的 Hook.
该 hook 主要是依赖 screenfull[1] 这个 npm 包进行实现的.
选择它的原因,估计有两个:
它的兼容性好,兼容各个浏览器的全屏 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;
}
边栏推荐
猜你喜欢
随机推荐
MASA Stack 第三期社区例会
mysql generates random name, mobile number, date
嵌入式软件开发的特点和流程
什么是硬件集成开发?硬件集成开发的核心有哪些?
EPIC是什么平台?
重谈联想5G编码投票事件
crm系统哪家好?好用的crm管理系统推荐
测试开发是什么,为什么现在这么吃香?
JMeter笔记6 | JMeter录制(配置代理)
谭中意:你知道 “开源女王” 是谁吗?
开篇-开启全新的.NET现代应用开发体验
方舟单机/管理员特殊物品指令代码大全
Smart Tool Management System
体验远超Hue,这才是技术人员最喜欢的SQL工具
SkiaSharp 之 WPF 自绘 粒子花园(案例版)
快捷键修改typora字体----自制脚本
产品结构设计优化模具简化结构总结
本机号码一键登录原理
vr虚拟仿真样板间极大节省出样成本-深圳华锐视点
我不写单元测试,被批了