Vue3使用hook封装媒体查询和事件监听,让开发更加丝滑

Vue3使用hook封装媒体查询和事件监听,让开发更加丝滑

js中媒体查询的主要方法是使用window对象下的matchMedia对象,查询语句和CSS媒体查询一样。

标题封装媒体查询

首先我们先看监听系统主题色的例子

  • 首先创建媒体查询对象
  • 根据查询结果设置对应的值
  • 然后建立监听事件,并且在退出时取消监听
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
}
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))
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vue1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值