matchMedia.js进阶指南:如何用addListener与removeListener监听响应式断点(完整教程)
【免费下载链接】matchMedia.jsmatchMedia polyfill for testing media queries in JS项目地址: https://gitcode.com/gh_mirrors/ma/matchMedia.js
matchMedia.js 是一款轻量级的 matchMedia polyfill 库,用于在 JavaScript 中检测 CSS 媒体查询是否生效。它的进阶能力在于通过addListener 与 removeListener监听响应式断点变化,让网页在用户缩放浏览器或旋转屏幕时自动切换布局逻辑。本教程将带你从零掌握它的完整用法。
为什么要用 matchMedia.js 监听断点?
CSS 媒体查询只能"改样式",却无法在断点切换时执行 JS 逻辑。比如:
- 桌面端初始化轮播图,平板端改为单列布局
- 大屏时加载高清背景图,小屏时切换为压缩图
- 侧边栏在断点两侧自动展开/折叠
window.matchMedia()是现代浏览器内置的 API,可返回媒体查询的匹配结果。而matchMedia.js的作用是为不支持该 API 的老旧浏览器提供兜底实现,并补上addListener/removeListener监听能力,让你在任何浏览器中都能优雅地响应断点变化。
项目由 Scott Jehl、Paul Irish、Nicholas Zakas 等知名开发者共同维护,MIT 协议开源,核心代码仅百余行,是 Respond.js、FormFactor 等经典库的底层依赖。
快速上手:引入 polyfill 两步走
matchMedia.js 由两个文件组成,各司其职:
| 文件 | 作用 |
|---|---|
| matchMedia.js | 基础 polyfill:实现matchMedia()与matches属性 |
| matchMedia.addListener.js | 扩展功能:补充addListener与removeListener |
两者都需要引入,顺序不能颠倒:
<script src="matchMedia.js"></script> <script src="matchMedia.addListener.js"></script>如果浏览器已原生支持addListener,扩展文件会直接短路退出(见 matchMedia.addListener.js),不会产生任何重复开销。
引入后,基础检测只需一行:
if (matchMedia('only screen and (max-width: 480px)').matches) { // 当前处于手机小屏断点 }更多检测示例(横屏检测、tv 介质类型等)可参考官方文档 README.md 中的 Usage 章节。
addListener 实战:监听 768px 断点变化
下面是最典型的响应式断点监听场景:当视口宽度跨过 768px 时执行回调。
var mql = window.matchMedia('(min-width: 768px)'); function handleBreakpoint(mql) { document.body.className = mql.matches ? 'layout-desktop' : 'layout-mobile'; } mql.addListener(handleBreakpoint); // 断点变化时被调用回调会接收一个 MediaQueryList 对象,其中mql.matches表示新状态。仓库内置的测试页 test/head.html 就演示了这个经典用法——跨过 768px 时用alert弹出匹配结果,方便你打开浏览器亲手验证。
工作原理:resize 事件 + 30ms 防抖
理解实现原理有助于写出更稳的代码。在 matchMedia.addListener.js 中:
- 第一个监听器注册时,才会在
window上挂一个resize监听(全局始终只有一个,保证性能); resize触发后通过setTimeout做30ms 防抖,避免拖拽窗口时回调风暴;- 遍历所有已注册查询,重新计算
matches,仅在状态翻转(true→false 或 false→true)时才触发监听器。
这套"防抖 + 状态翻转"机制,意味着你的回调只在真正跨越断点的那一瞬间执行一次——这正是响应式断点监听最需要的行为。
removeListener 详解:优雅卸载监听器
页面组件销毁、SPA 路由切换、重复初始化时,必须及时移除监听器,否则会出现:
- 回调多次执行(同一事件被触发 N 次)
- 已销毁的 DOM 节点被反复操作,抛出异常
- 全局 resize 监听无法释放,造成内存泄漏隐患
var mql = window.matchMedia('(min-width: 768px)'); var handler = function(mql) { /* 切换布局 */ }; mql.addListener(handler); // 组件卸载时: mql.removeListener(handler); // 传入同一个函数引用才能成功移除关键点:removeListener通过引用比较(listeners[i] === listener,见 源码实现)来定位要移除的回调。因此切勿传入匿名函数,否则永远匹配不上:
// 错误示范:移除失败 mql.addListener(function(mql) { /* ... */ }); mql.removeListener(function(mql) { /* ... */ }); // 这是两个不同的函数 // 正确做法:保存引用 var handler = function(mql) { /* ... */ }; mql.addListener(handler); mql.removeListener(handler);另外注意:即使所有监听器都被移除,源码中的全局resize监听仍会保留(isListening不会复位),这是已知的设计取舍——对于小体积 polyfill 而言影响微乎其微,但了解这一点能帮你排查"为什么 resize 事件还在跑"这类问题。
常见场景:监听多个响应式断点
同一页面往往需要同时监听多个断点,为每个查询独立管理监听器即可:
var mqTablet = matchMedia('(min-width: 768px)'); var mqDesktop = matchMedia('(min-width: 1200px)'); var onTablet = function(mql) { console.log('平板断点:', mql.matches); }; var onDesktop = function(mql) { console.log('桌面断点:', mql.matches); }; mqTablet.addListener(onTablet); mqDesktop.addListener(onDesktop); // 需要时精准卸载 mqTablet.removeListener(onTablet);每个matchMedia()调用都会生成独立的 MediaQueryList,监听器互不干扰(查询列表管理逻辑见 matchMedia.addListener.js)。
性能与兼容性注意事项
- 防抖已内置:源码固定 30ms 防抖窗口(handleChange),你无需再叠加节流;
- 单次 matchMedia 调用极快:仓库测试页用 JSLitmus 对
matchMedia做了基准测试(见 test/head.html),性能无忧; - IE ≤ 8 的降级:若浏览器不支持 CSS3 媒体查询,
addListener会直接返回不注册监听(见 hasMediaQueries 判断),检测类功能不受影响; - 原生优先:所有浏览器(Chrome、Firefox、Safari 等)已原生支持
matchMedia与addListener时,polyfill 自动让位,零副作用; - 版本与许可信息见 package.json,当前发布版本为 0.3.2,MIT 协议可自由商用。
总结
matchMedia.js 用极小的体积解决了"JS 响应断点"这一经典难题:
- matchMedia.js提供
matches一次性检测能力,兼容老浏览器; - matchMedia.addListener.js补齐
addListener/removeListener,配合 resize 防抖实现可靠的断点监听; - 记住三件事:保存回调引用、销毁时及时 removeListener、只在状态翻转时才干活。
掌握这套组合,你就能在任意项目中轻松实现响应式断点的 JS 逻辑监听。
【免费下载链接】matchMedia.jsmatchMedia polyfill for testing media queries in JS项目地址: https://gitcode.com/gh_mirrors/ma/matchMedia.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考