1036 字
5 分钟
window.matchMedia() - 在 JavaScript 中检测和监听 CSS 媒体查询
简介
window.matchMedia() 是一个强大的 JavaScript API,用于在 JavaScript 中检测和监听 CSS 媒体查询的状态。它让你能够在 JS 中使用 CSS 媒体查询的逻辑,实现更灵活的响应式设计。
基本语法
const mediaQueryList = window.matchMedia('(媒体查询字符串)');返回值
返回一个 MediaQueryList 对象,包含以下属性和方法:
- matches: 布尔值,表示当前是否匹配媒体查询
- media: 媒体查询字符串
- addEventListener(): 监听媒体查询状态变化
- removeEventListener(): 移除监听器
常见用法
1. 检测屏幕宽度
// 检测是否是移动端const isMobile = window.matchMedia('(max-width: 768px)');
if (isMobile.matches) { console.log('当前是移动端视图');} else { console.log('当前是桌面端视图');}2. 监听屏幕变化
const mediaQuery = window.matchMedia('(max-width: 768px)');
// 监听变化mediaQuery.addEventListener('change', (e) => { if (e.matches) { console.log('切换到移动端视图'); } else { console.log('切换到桌面端视图'); }});3. 检测深色模式
const darkMode = window.matchMedia('(prefers-color-scheme: dark)');
// 初始检测if (darkMode.matches) { document.body.classList.add('dark-theme');}
// 监听系统主题变化darkMode.addEventListener('change', (e) => { if (e.matches) { document.body.classList.add('dark-theme'); } else { document.body.classList.remove('dark-theme'); }});4. 检测设备特性
// 检测高分辨率屏幕const isRetina = window.matchMedia('(min-resolution: 2dppx)');
// 检测屏幕方向const isLandscape = window.matchMedia('(orientation: landscape)');
// 检测触摸设备const hasTouch = window.matchMedia('(pointer: coarse)');
// 检测打印模式const isPrint = window.matchMedia('print');5. 复杂的媒体查询
// 组合多个条件const isTablet = window.matchMedia( '(min-width: 768px) and (max-width: 1024px) and (orientation: portrait)');
// 使用 CSS4 媒体查询const hasHover = window.matchMedia('(hover: hover)');const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');实际应用示例
响应式组件加载
class ResponsiveComponent { constructor() { this.desktop = window.matchMedia('(min-width: 1024px)'); this.tablet = window.matchMedia('(min-width: 768px) and (max-width: 1023px)'); this.mobile = window.matchMedia('(max-width: 767px)');
this.init(); this.addListeners(); }
init() { if (this.desktop.matches) { this.loadDesktopFeatures(); } else if (this.tablet.matches) { this.loadTabletFeatures(); } else { this.loadMobileFeatures(); } }
addListeners() { this.desktop.addEventListener('change', () => this.init()); this.tablet.addEventListener('change', () => this.init()); this.mobile.addEventListener('change', () => this.init()); }
loadDesktopFeatures() { console.log('加载桌面端功能'); // 加载复杂的可视化组件、大图等 }
loadTabletFeatures() { console.log('加载平板功能'); // 加载适合平板的中等复杂度功能 }
loadMobileFeatures() { console.log('加载移动端功能'); // 加载轻量级组件 }}
// 使用const app = new ResponsiveComponent();React Hook 示例
// 自定义 Hookfunction useMediaQuery(query) { const [matches, setMatches] = React.useState( () => window.matchMedia(query).matches );
React.useEffect(() => { const mediaQuery = window.matchMedia(query); const handler = (e) => setMatches(e.matches);
// 立即检查 setMatches(mediaQuery.matches);
// 添加监听 mediaQuery.addEventListener('change', handler);
// 清理 return () => mediaQuery.removeEventListener('change', handler); }, [query]);
return matches;}
// 使用示例function App() { const isMobile = useMediaQuery('(max-width: 768px)'); const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
return ( <div className={isDarkMode ? 'dark-theme' : 'light-theme'}> {isMobile ? <MobileNav /> : <DesktopNav />} </div> );}Vue 3 Composition API 示例
// 自定义组合式函数import { ref, onMounted, onUnmounted } from 'vue';
export function useMediaQuery(query) { const matches = ref(false); let mediaQuery = null;
const updateMatches = (e) => { matches.value = e.matches; };
onMounted(() => { mediaQuery = window.matchMedia(query); matches.value = mediaQuery.matches; mediaQuery.addEventListener('change', updateMatches); });
onUnmounted(() => { if (mediaQuery) { mediaQuery.removeEventListener('change', updateMatches); } });
return matches;}
// 使用示例export default { setup() { const isMobile = useMediaQuery('(max-width: 768px)'); const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
return { isMobile, isDarkMode }; }};优点
- 性能优越:比
resize事件更高效,不会频繁触发 - 精确匹配:使用 CSS 媒体查询的完整功能,与 CSS 保持一致
- 实时响应:自动监听变化,无需手动轮询
- 浏览器原生:无需额外库,减少依赖
注意事项
浏览器兼容性
- 现代浏览器都支持
window.matchMedia() - IE10+ 支持(但需要使用
addListener而不是addEventListener)
兼容性处理
// IE10 兼容性处理function addMediaQueryListener(mq, callback) { if (mq.addEventListener) { mq.addEventListener('change', callback); } else if (mq.addListener) { // IE10 兼容 mq.addListener(callback); }}
// 移除监听器function removeMediaQueryListener(mq, callback) { if (mq.removeEventListener) { mq.removeEventListener('change', callback); } else if (mq.removeListener) { // IE10 兼容 mq.removeListener(callback); }}最佳实践
- 缓存媒体查询对象:避免重复创建相同的媒体查询
- 及时清理监听器:在组件销毁时移除监听器,防止内存泄漏
- 与 CSS 保持同步:确保 JS 中的断点与 CSS 中的断点一致
- 渐进增强:先实现 CSS 响应式,再用 JS 增强功能
总结
window.matchMedia() API 是实现真正响应式 JavaScript 逻辑的强大工具。它让 JS 代码能够像 CSS 一样响应媒体查询的变化,为构建现代响应式 Web 应用提供了原生、高效的解决方案。通过合理使用这个 API,我们可以创建更加智能和适应性强的用户界面。
window.matchMedia() - 在 JavaScript 中检测和监听 CSS 媒体查询
https://fuwari.vercel.app/posts/window-metchmedia/