React:媒体查询的自定义钩子📱💻
今天我们将制作一个 React hook,它将接受媒体查询并返回该查询解析为 true 还是 false。
我想要实现的目标
这里的目标是实现一个当媒体内容发生变化时会更新的状态。这主要针对屏幕尺寸,以便我们实现一些很棒的响应式功能,但也适用于任何媒体查询。
媒体查询
你也许会想,媒体查询*只适用于屏幕尺寸,或者媒体查询到底是什么?那就让我们快速了解一下。
如果我们前往MDN,我建议这始终是开始的地方,我们会看到我们可以使用的东西的完整列表,从aspect-ratio
到orientation
甚至resolution
。
/* Minimum aspect ratio */
@media (min-aspect-ratio: 8/5) {
div {
background: #9af; /* blue */
}
}
/* Maximum aspect ratio */
@media (max-aspect-ratio: 3/2) {
div {
background: #9ff; /* cyan */
}
}
/* Exact aspect ratio, put it at the bottom to avoid override*/
@media (aspect-ratio: 1/1) {
div {
background: #f9a; /* red */
}
}
您可以在 MDN 上查看列表并了解所有不同属性的作用,我将重点介绍其中 3 个我认为很重要但经常被忽视的属性。
偏好配色方案
prefers -color-scheme CSS 媒体功能用于检测用户是否请求了浅色或深色主题。
这意味着我们可以改变我们网站的整体外观和感觉以匹配用户请求的主题,这不仅适用于苦行者,而且如果用户的眼睛敏感,他们可能会默认请求黑暗模式,我们可以提供更好、更无缝的用户体验。
偏好对比
prefers -contrast CSS 媒体功能用于检测用户是否要求以更高(或更低)的对比度呈现网页内容。
此功能目前仅适用于 Safari,但后续会支持,而且它还能让您的应用随时运行。此功能对可访问性影响巨大。如果用户因为需要更高的对比度而无法阅读您的文字,那么您的网站对他们来说就毫无意义。
喜欢减少运动
prefers-reduced-motion CSS 媒体功能用于检测用户是否要求系统尽量减少其使用的非必要运动量。
再次回到可访问性方面,你注意到一个规律了吗?动画很酷,我喜欢在我的网站和应用中添加动画,但有些人会晕动症。有了这项功能,我们可以简单地将动画从幻灯片改为淡入淡出,甚至可以完全移除动画。
钩子
这个钩子相当简单,它只会用到useState
和useEffect
以及matchMedia
。我会留给你通读代码,之后我会稍微讨论一下try
-catch
部分。
export default function useMediaQuery(initalQuery: string) {
const [query, setQuery] = useState(initalQuery);
const [matches, setMatches] = useState(false);
// check query and listen for media change.
useEffect(() => {
if (!query) return;
const _onChange = (mql: MediaQueryListEvent) => {
setMatches(mql.matches);
};
const mql = window.matchMedia(query);
setMatches(mql.matches);
try {
mql.addEventListener("change", _onChange);
} catch {
mql.addListener(_onChange);
}
return () => {
try {
mql.removeEventListener("change", _onChange);
} catch {
mql.removeListener(_onChange);
}
};
}, [query]);
return [matches, setQuery] as const;
}
所以try
——catch
规范最初制定时,addListener(func)
是监听媒体变化的方式,但在 2015 年,也就是 IE11 发布两年后,规范进行了修改,将其与其他事件监听器标准化,于是addEventListener('change, func)
就有了新的监听方式。我们先尝试新的方式,如果失败,就用旧的方式。这意味着在所有现代浏览器中,我们都会立即采用新的方式,而在旧浏览器 IE11 中,我们需要多等待几毫秒才能添加监听器。
示例
下面是几个例子,请随意浏览代码并提出您可能遇到的任何问题。
鳍
好了,我们完成了一个 React Hook,它会将媒体查询的结果返回到状态中,并在媒体发生变化时更新该状态。这是一个非常有用的 Hook,也是学习如何编写媒体 Hook 的简单入门之选。
一如既往,如果您有任何疑问或认为我做错了什么,请随时留言。感谢大家阅读到这里。
参考文献
- https://css-tricks.com/touch-devices-not-judged-size/
- https://developer.mozilla.org/en-US/docs/Web/CSS/@media
- https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia