当前位置:网站首页>那些关于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
边栏推荐
- New graduate students, great experience in reading English literature, worthy of your collection
- 【Kaggle】Classify Leaves
- Wildcard SSL/TLS certificate
- 微服务负载均衡器Ribbon
- LTE time domain and frequency domain resources
- 织梦发布文章提示body has not allow words错误
- Acrel-5010重点用能单位能耗在线监测系统在湖南三立集团的应用
- idea插件generateAllSetMethod一键生成set/get方法以及bean对象转换
- excel高级绘图技巧100讲(二十二)-如何对不规则数据进行分列
- 数字孪生北京故宫,元宇宙推进旅游业进程
猜你喜欢
LTE time domain and frequency domain resources
MySQL 中出现的字符编码错误 Incorrect string value: ‘\x\x\x\x‘ for column ‘x‘
关于Request复用的那点破事儿。研究明白了,给你汇报一下。
【Dart】dart之mixin探究
Buttons with good user experience should not have hover state on mobile phones
Interview Blitz 70: What are sticky packs and half packs?How to deal with it?
[Energy Conservation Institute] Ankerui Food and Beverage Fume Monitoring Cloud Platform Helps Fight Air Pollution
外骨骼机器人(七):标准步态数据库
【节能学院】数据机房中智能小母线与列头柜方案的对比分析
Zheng Xiangling, Chairman of Tide Pharmaceuticals, won the "2022 Outstanding Influential Entrepreneur Award" Tide Pharmaceuticals won the "Corporate Social Responsibility Model Award"
随机推荐
Internet使用的网络协议是什么
OSG笔记:设置DO_NOT_COMPUTE_NEAR_FAR,手动计算远近平面
"No title"
The Internet giant development process
面试突击70:什么是粘包和半包?怎么解决?
泰德制药董事长郑翔玲荣膺“2022卓越影响力企业家奖” 泰德制药荣获“企业社会责任典范奖”
STAHL touch screen repair all-in-one display screen ET-316-TX-TFT common faults
进行交互或动画时如何选择Visibility, Display, and Opacity
Postman 批量测试接口详细教程
360借条安全专家:陌生微信好友不要轻易加贷款推广多是诈骗
通俗解释:什么是临床预测模型
30+的女性测试人面试经验分享
excel高级绘图技巧100讲(二十二)-如何对不规则数据进行分列
Use WeChat official account to send information to designated WeChat users
Zheng Xiangling, Chairman of Tide Pharmaceuticals, won the "2022 Outstanding Influential Entrepreneur Award" Tide Pharmaceuticals won the "Corporate Social Responsibility Model Award"
Acrel-5010重点用能单位能耗在线监测系统在湖南三立集团的应用
外骨骼机器人(七):标准步态数据库
微服务负载均衡器Ribbon
自定义指令,获取焦点
徒步,治好了我的精神内耗