MediaQueryList 接口是媒体查询响应式核心,window.matchMedia()仅是创建其实例的工厂函数;它提供matches属性和addEventListener()方法实现状态监听,需手动检查初始状态且注意语法正确性。
很多人以为 window.matchMedia() 是“媒体查询 API”,其实它只是创建 MediaQueryList 实例的工厂函数。真正响应变化、承载状态的是返回的 MediaQueryList 对象——它有 matches 属性和 addEventListener() 方法,这才是可监听、可响应的关键。
直接读 window.matchMedia('(max-width: 768px)').matches 只能取快照,不监听;必须用 addListener()(旧)或 addEventListener('change', ...)(新)才能响应尺寸变化。
addListener() 在 Chrome 109+、Firefox 117+ 已被弃用,但仍有大量老项目在用,兼容性需留意addEventListener() 是标准方式,但 IE 完全不支持,如需支持 IE,必须降级 fallbackMediaQueryList 实例可复用:同一查询字符串多次调用 matchMedia() 返回不同对象,不要重复创建监听器下面这段代码在现代浏览器中稳定工作,监听从桌面到移动的切换:
const mql = window.matchMedia('(max-width: 768px)');
const handleMediaChange = (e) => {
if (e.matches) {
console.log('进入移动端视图');
} else {
console.log('回到桌面视图'
);
}
};
// 使用 addEventListener(推荐)
mql.addEventListener('change', handleMediaChange);
// 初始状态也要检查(change 不触发初始匹配)
if (mql.matches) {
handleMediaChange(mql);
}
注意:不能只靠事件回调判断初始状态——change 只在查询结果翻转时触发,页面加载时可能已处于目标断点内,必须手动检查 mql.matches 并调用一次处理函数。
错误写法会导致 mql.matches 永远为 false,且不报错,极难排查:
window.matchMedia('max-width: 768px') ❌ 缺少括号 → 应为 '(max-width: 768px)'
window.matchMedia('(min-width: 768px) and (max-width: 1024px)') ✅ 正确,多条件用 and 连接window.matchMedia('(width ❌ CSS 媒体查询不支持运算符写法screen、print 等媒体类型时,必须写全:'screen and (max-width: 768px)'
调试技巧:打印 mql.media 看实际解析的字符串,确认是否与预期一致。
组件卸载(如 React unmount、Vue destroyed)时,若没移除监听器,MediaQueryList 仍持有回调引用,可能导致闭包中 DOM 节点无法回收。
mql.removeEventListener('change', handleMediaChange)
addListener() 时,用 removeListener() 配对,不能混用useEffect 的 cleanup 函数里移除;Vue 3 的 onBeforeUnmount 同理一个容易被忽略的点:MediaQueryList 本身不会自动销毁,哪怕窗口关闭或 iframe 卸载,只要 JS 上下文还在,它就持续存在。