当前位置:网站首页>那些关于DOM的常见Hook封装(二)
那些关于DOM的常见Hook封装(二)
2022-08-01 20:57:00 【GopalFeng】
本文是深入浅出 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;
}
参考资料
[1]
screenfull: https://www.npmjs.com/package/screenfull
边栏推荐
- Go 语言中常见的坑
- 数字孪生北京故宫,元宇宙推进旅游业进程
- New graduate students, great experience in reading English literature, worthy of your collection
- 算法---解码方法(Kotlin)
- 数据库单字段存储多个标签(位移操作)
- OSG笔记:设置DO_NOT_COMPUTE_NEAR_FAR,手动计算远近平面
- 4.1 配置Mysql与注册登录模块
- Interview Blitz 70: What are sticky packs and half packs?How to deal with it?
- 【个人作品】无线网络图传模块
- 自定义指令,获取焦点
猜你喜欢

Digital twin Beijing the imperial palace, yuan universe is the process of tourism

What is the difference between a utility model patent and an invention patent?Understand in seconds!

Use WeChat official account to send information to designated WeChat users

StringTable详解 串池 性能调优 字符串拼接

MySQL 中出现的字符编码错误 Incorrect string value: ‘\x\x\x\x‘ for column ‘x‘

Postman 批量测试接口详细教程

Wildcard SSL/TLS certificate

乐观锁批量跟新 纯SQL

SIPp installation and use

响应式织梦模板美容整形类网站
随机推荐
Pytorch框架学习记录10——线性层
有点奇怪!访问目的网址,主机能容器却不行
乐观锁批量跟新 纯SQL
线上问题排查常用命令,总结太全了,建议收藏!!
Qt设置应用程序开机自启 解决设置失败原因
技术栈概览
Buttons with good user experience should not have hover state on mobile phones
WhatsApp group sending actual combat sharing - WhatsApp Business API account
Goroutine Leaks - The Forgotten Sender
STAHL触摸屏维修一体机显示屏ET-316-TX-TFT常见故障
[Energy Conservation Institute] Ankerui Food and Beverage Fume Monitoring Cloud Platform Helps Fight Air Pollution
98. Embedded controller EC actual combat EC development board development completed
"Torch" tensor multiplication: matmul, einsum
Pytorch框架学习记录13——利用GPU训练
myid file is missing
泰德制药董事长郑翔玲荣膺“2022卓越影响力企业家奖” 泰德制药荣获“企业社会责任典范奖”
微信小程序云开发|个人博客小程序
1374. 生成每种字符都是奇数个的字符串 : 简单构造模拟题
Addition, Subtraction, Multiplication of Large Integers, Multiplication and Division of Large Integers and Ordinary Integers
30+的女性测试人面试经验分享