Safari中Angular Material报addEventListener不存在如何修复
问题核心成因
- 旧版本Safari(含iOS 12及更早的移动端Safari、macOS 11.0之前的桌面端Safari)的
MediaQueryList对象未实现W3C标准的addEventListener、removeEventListener监听接口 - 这类老旧浏览器仅支持已被标记为废弃的
addListener、removeListener旧API,直接调用不存在的标准方法时,就会抛出this.mobileQuery.addEventListener is not a function的运行时错误,removeEventListener的调用也会触发同类型问题 - 参考的官方实现未做旧版浏览器的兼容兜底,仅在全量支持标准MediaQueryList接口的现代浏览器上可正常运行
兼容修复方案
- 对绑定监听、移除监听的逻辑做API能力判断,优先调用标准方法,在旧版Safari场景下自动降级到可用的旧API,无需引入额外的polyfill依赖
- 新旧API的触发时机、回调入参完全一致,不需要修改原有断点判断的业务逻辑
- 修复后的核心实现代码:
public mobileQuery: MediaQueryList; private _mobileQueryListener: () => void; constructor(changeDetectorRef: ChangeDetectorRef, media: MediaMatcher) { this.mobileQuery = media.matchMedia('(max-width: 992px)'); this._mobileQueryListener = () => changeDetectorRef.detectChanges(); // 绑定监听前判断API能力 if (this.mobileQuery.addEventListener) { this.mobileQuery.addEventListener('change', this._mobileQueryListener); } else { // 旧版Safari降级逻辑 this.mobileQuery.addListener(this._mobileQueryListener); } } ngOnDestroy(): void { // 移除监听前判断API能力 if (this.mobileQuery.removeEventListener) { this.mobileQuery.removeEventListener('change', this._mobileQueryListener); } else { // 旧版Safari降级逻辑 this.mobileQuery.removeListener(this._mobileQueryListener); } }
落地注意事项
- 不需要强行给
MediaQueryList手动补充不存在的方法,能力判断的兼容方式无额外副作用,不会增加项目包体积 - 兼容逻辑同时覆盖现代浏览器、旧版Safari的运行场景,不会出现重复绑定监听导致的内存泄漏、频繁触发变更检测的性能问题
- 原有992px的断点判断逻辑完全不受兼容代码影响,sidenav的折叠、展开行为不会出现偏差
内容的提问来源于stack exchange,提问作者Devla
相关产品推荐
相关产品推荐

