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 示例#

// 自定义 Hook
function 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
};
}
};

优点#

  1. 性能优越:比 resize 事件更高效,不会频繁触发
  2. 精确匹配:使用 CSS 媒体查询的完整功能,与 CSS 保持一致
  3. 实时响应:自动监听变化,无需手动轮询
  4. 浏览器原生:无需额外库,减少依赖

注意事项#

浏览器兼容性#

  • 现代浏览器都支持 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);
}
}

最佳实践#

  1. 缓存媒体查询对象:避免重复创建相同的媒体查询
  2. 及时清理监听器:在组件销毁时移除监听器,防止内存泄漏
  3. 与 CSS 保持同步:确保 JS 中的断点与 CSS 中的断点一致
  4. 渐进增强:先实现 CSS 响应式,再用 JS 增强功能

总结#

window.matchMedia() API 是实现真正响应式 JavaScript 逻辑的强大工具。它让 JS 代码能够像 CSS 一样响应媒体查询的变化,为构建现代响应式 Web 应用提供了原生、高效的解决方案。通过合理使用这个 API,我们可以创建更加智能和适应性强的用户界面。

window.matchMedia() - 在 JavaScript 中检测和监听 CSS 媒体查询
https://fuwari.vercel.app/posts/window-metchmedia/
作者
Lorem Ipsum
发布于
2025-11-03
许可协议
CC BY-NC-SA 4.0