3.7 Browser – useMediaQuery
https://vueuse.org/core/useMediaQuery/
作用
响应式的媒体查询。一旦你创建了一个MediaQueryList
对象,你就可以得到查询的结果,或者在结果变化时收到通知。
媒体查询我们一般都是用来根据窗口大小,来适配不同的UI。
比如:
@media screen and (max-width: 300px) {
body {
background-color:lightblue;
}
}
官方示例
import { useMediaQuery } from '@vueuse/core'
const isLargeScreen = useMediaQuery('(min-width: 1024px)') // 窗口是否是大屏幕(最小宽度1024px)
const isPreferredDark = useMediaQuery('(prefers-color-scheme: dark)') // 窗口是否是黑暗模式
当屏幕大小变化时,isLargeScreen
也会响应式改变。isPreferredDark
也是同样的。
源码分析
比起如何实现,这段代码中,更重要的是知道**“媒体查询”**包括哪些?
export function useMediaQuery(query: MaybeComputedRef<string>, options: ConfigurableWindow = {}) {
const { window = defaultWindow } = options
// window.matchMedia 和 @media是等效的
const isSupported = useSupported(() => window && 'matchMedia' in window && typeof window.matchMedia === 'function')
let mediaQuery: MediaQueryList | undefined
const matches = ref(false)
const cleanup = () => {
if (!mediaQuery)
return
if ('removeEventListener' in mediaQuery)
mediaQuery.removeEventListener('change', update)
else
mediaQuery.removeListener(update)
}
/**
* update 是 watchEffect的回调,所以其中所有的响应式变量发生变化都会触发update的执行。matches,query
*
*/
const update = () => {
if (!isSupported.value)
return
cleanup()
// matchMedia() 返回一个新的 MediaQueryList 对象,表示指定的媒体查询字符串解析后的结果
// 包括两个属性:1 media:查询语句的内容; 2 matches:用于检测查询结果
mediaQuery = window!.matchMedia(resolveRef(query).value)
matches.value = mediaQuery.matches
// 根据mediaQuery支持的方法来注册监听。
if ('addEventListener' in mediaQuery)
mediaQuery.addEventListener('change', update)
else
mediaQuery.addListener(update)
}
watchEffect(update)
// 这个方法内部调用vue3提供的一个方法onScopeDispose。当作用域销毁时,执行回调函数,也就是cleanup
tryOnScopeDispose(() => cleanup())
return matches
}
整体来看只做了两件事,监听和取消监听。
- 当查询对象发生变化,或者查询结果发生变化,都会重新注册。
- 在重新注册的时候,以及
effect
作用域销毁的时候,取消监听。