You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

31 lines
893 B

import { onBeforeUnmount, onMounted, ref, type Ref } from 'vue'
/**
* 响应式地跟踪 CSS 媒体查询匹配状态。
*
* SSR 安全:服务端渲染期间始终返回 `false`,避免 hydration mismatch;
* 客户端 `onMounted` 之后才订阅 `matchMedia`。
*
* @param query - 合法 CSS media query 字符串
* @returns Ref<boolean> - 当前是否匹配
*/
export function useMediaQuery(query: string): Ref<boolean> {
const matches = ref(false)
let mql: MediaQueryList | null = null
const handler = (e: MediaQueryListEvent) => {
matches.value = e.matches
}
onMounted(() => {
if (typeof window === 'undefined' || !window.matchMedia) return
mql = window.matchMedia(query)
matches.value = mql.matches
mql.addEventListener('change', handler)
})
onBeforeUnmount(() => {
mql?.removeEventListener('change', handler)
})
return matches
}