使用JS媒体查询,MediaQueryList全解析

4,814 阅读3分钟

本文来自我的博客

什么是MediaQueryList

一个MediaQueryList对象在一个document上维持着一系列的媒体查询,并负责处理当媒体查询在其document上发生变化时向监听器进行通知的发送。

如果你需要以编程方式来检测一个document上的媒体查询的值的变化,这个MediaQueryList对象使得通过观察其document而检测它的媒体查询的值的变化成为可能,而不是周期性地对这些媒体查询的值进行检查。

简单来说,MediaQueryList就是提供给JavaScript进行媒体查询的方法

兼容性方面也挺好

先来看看MediaQueryList的属性和方法

属性

  • matches 返回媒体查询的结果
  • media 返回媒体查询的内容
  • onchange 媒体查询状态变化时触发的事件

方法

  • addListener() 当媒体查询状态变化时触发的自定义回调
  • removeListener() 移除自定义回调

matches

matchesMediaQueryList的只读属性,返回一个布尔值,当媒体查询匹配时返回ture,反之false

先要创建一个MediaQueryList对象

const mql = window.matchMedia("(max-width:1600px)");

通过matches属性获取媒体查询的结果

if (mql.matches) console.log("屏幕宽度小于1600px"); // 如果刚好1600也返回true
else console.log("屏幕宽度大于1600px");

通过这个方式可以很容易的判断当前系统的主题

let pref = window.matchMedia("(prefers-color-scheme: light)");
if (pref.matches) console.log("light");
pref = window.matchMedia("(prefers-color-scheme: dark)");
if (pref.matches) console.log("dark");

在实现页面主题的切换功能时可以用到

media

media属性会返回填写的媒体查询匹配规则

const mql = window.matchMedia("(max-width:1600px)");
console.log(mql.media); // (max-width: 1600px)

addListener/removeListener

addListener添加自定义回调,在媒体查询的状态改变时会调用回调

const mql = window.matchMedia("(max-width:1600px)");
const cb = e => {
  if (e.matches) console.log("屏幕宽度小于1600px");
  else console.log("屏幕宽度大于1600px");
};
mql.addListener(cb);
// 移除回调函数
mql.removeListener(cb);

在页面加载完成后,不会触发此回调,一定得手动拖动窗口大小后才会触发

有小伙伴就要问了,onchange属性呢,且容我细细道来

onchange

先来看代码

const mql = window.matchMedia("(max-width:1600px)");
const cb = e => {
  if (e.matches) console.log("屏幕宽度小于1600px");
  else console.log("屏幕宽度大于1600px");
};
mql.onchange = cb;

在Chrome上一切正常,然而在Safari上毫无反应

在看看Can i use

为什么兼容性突然就变成这样了?

在使用addListener的时候,我发现了在Webstorm里addListener居然划了横线标注了废弃的方法

不仅addListenerremoveListener也废弃了,同时发现了两个新方法addEventListenerremoveEventListener

addEventListener/removeEventListener

addEventListener的使用方式和DOM2级事件绑定方式相同

const mql = window.matchMedia("(max-width:1600px)");
const cb = e => {
  if (e.matches) console.log("屏幕宽度小于1600px");
  else console.log("屏幕宽度大于1600px");
};
mql.addEventListener("change", cb);
// mql.removeEventListener("change", cb);

在Chrome上一切正常,在Safafi上就报错了mql.addEventListener is not a function,这也许能解释为什么onchange兼容性不好了

同时我发现,使用addListener方法添加的事件,参数e在Chrome上和Safari上也是两个不同的东西

在Chrome上,它是一个Event对象,在Safari上只是包含了matchesmedia属性的对象,在看看兼容性

看上去Chrome也是才支持的

在MDN上是这样写的

MediaQueryList.addListener()方法只是为了向后兼容EventTarget.addEventListener()的一个别名,在老的浏览器上应该使用addListener而不是addEventListener,因为MediaQueryList只从新的浏览器继承EventTarget

我想这只是为了规范化吧,看来新的浏览器Chrome 80也不够新啊,还是老老实实看着标灰划个线用addListener就行了


参考资料:

MDN:developer.mozilla.org/zh-CN/docs/…