js中媒体查询的主要方法是使用window对象下的matchMedia
对象,查询语句和CSS媒体查询一样。
封装媒体查询
首先我们先看监听系统主题色的例子
- 首先创建媒体查询对象
- 根据查询结果设置对应的值
- 然后建立监听事件,并且在退出时取消监听
export const useTheme = () => { // 首先创建媒体查询对象 const themeMedia = matchMedia("(prefers-color-scheme: light)") // 根据查询结果设置对应的值 const theme = ref(themeMedia.matches ? 'light' : 'dark') const onChange = (e: MediaQueryListEvent) => theme.value = e.matches ? 'light' : 'dark' watchEffect((onCleanup) => { // 然后建立监听事件 themeMedia.addEventListener('change', onChange) // 并且在退出时取消监听 onCleanup(() => themeMedia.removeEventListener('change', onChange)) }) return theme; }
我们测试下
const theme = useTheme() watchEffect(() => console.log(theme.value, 'theme'))
如果我们其他查询查询,我们需要重新设置新的值,所以,接下来我们封装一个更通用的媒体查询hook,如下,
export const useMatchMedia = (query: string) => { const themeMedia = matchMedia(query) const match = ref(themeMedia.matches) const onChange = (e: MediaQueryListEvent) => match.value = e.matches watchEffect((onCleanup) => { themeMedia.addEventListener('change', onChange) onCleanup(() => themeMedia.removeEventListener('change', onChange)) }) return match }
这个例子里,我们不再对特定的媒体查询值做处理,同时,我们将查询语句作为动态变量,将结果处理交给开发者。
我们使用通用的hook重写监听系统主题色的hook,如下:
export const useTheme = () => { const theme = useMatchMedia("(prefers-color-scheme: light)") const theme = ref(themeMedia.matches ? 'light' : 'dark') return theme ? 'light' : 'dark' }
是不是这样更简洁了。
封装事件监听
接下来,我们再看第二个简单的例子,监听网络状态。
监听网络状态,主要通过监听navigator.onLine
的变化,值的变化可以通过addEventListener方法,
有了封装媒体查询的例子,我们首先会想到封装事件监听的值的变化可以通过addEventListener方法,成为一个通用的钩子函数。如下:
export const useEventListener = <K extends keyof WindowEventMap>( target: K, listener: (ev: WindowEventMap[K]) => any ) => { watchEffect((onCleanup) => { addEventListener(target, listener) onCleanup(() => removeEventListener(target, listener)) }) }
此时,我们就可以这样封装监听网络状态的hook了
export const useNetWork = () => { const isOnLine = ref(navigator.onLine) const setOnLine = () => isOnLine.value = true const setOffLine = () => isOnLine.value = false useEventListener('online', setOnLine) useEventListener('offline', setOffLine) return isOnLine }
我们测试下
const isOnLine = useNetWork() watchEffect(() => console.log(isOnLine.value, 'isOnLine')) <h1 v-if="isOnLine">onLine</h1> <h1 v-else>offLine</h1>
接下来我们测试下其他的监听事件,比如监听scroll事件。
useEventListener('scroll', () => console.log('scroll'))
功能是正常的,但是顺理成章,我们还需要写一个防抖函数
export const debounce = ( fn: (...args: any[]) => void, delay: number ) => { let timer: NodeJS.Timeout return (...args: any[]) => { if (timer) clearTimeout(timer) timer = setTimeout(() => { fn.apply(this, args) }, delay) } }
useEventListener('scroll', debounce(() => console.log('scroll'), 200))
好了今天的分享到这了,如果文章中有纰漏的地方欢迎指正,我及时修改,感谢你的阅读
觉得文章还不错点个赞再走吧,十分感谢