window.matchMedia响应分辨率和操作系统主题模式变化
作用
- 使用 window.matchMedia()在 JavaScript 中进行 CSS 媒体查询匹配。
- 响应操作系统的主题变化
有些时候,除了 CSS 之外,你还需要在 JavaScript 中做一些匹配 CSS 媒体查询的事情。
window.matchMedia()返回的属性
js
// 示例
const mql = window.matchMedia('screen and (max-width: 765px)')
window.matchMedia()返回一个 MediaQueryList 对象,其中包含一些方法和属性,最常用的是 matches 属性。这是一个布尔属性,如果媒体查询与当前窗口的状态相匹配,则返回 true,如果不匹配则返回 false。
| 属性 | 类型 | 说明 |
|---|---|---|
| matches | boolean | 如果当前窗口状态与 css 查询字符串中定义的条件匹配,则返回 true,否则返回 false |
| media | string | 返回序列化的媒体列表. 如: 'screen and (max-width: 765px)' |
js
var mql = window.matchMedia('screen and (min-width: 800px)')
if (mql.matches) {
// 如果媒体查询匹配, 则说明当前屏幕最小宽度未800像素
alert('窗口 >= 800px')
} else {
// 做其他的事情
}
window.matchMedia()返回的方法
| 方法 | 说明 |
|---|---|
| addListener(function) | 增加响应函数,每当窗口发生变化时就会执行 |
| removeListener(function) | 删除先前的响应函数 |
addEventListener()。通过一个函数来包装我们想要运行的代码,并将其添加到 addListener(),现在只要当前窗口状态的任何变化导致与定义的 CSS 媒体查询匹配,我们的函数就会被执行。
我们的代码现在不仅可以在运行时对 CSS 媒体查询匹配做出反应,而且可以在窗口状态发生变化时做出反应。
响应屏幕分辨率变化
js
function mediaqueryresponse(mql) {
if (mql.matches) {
console.log('屏幕宽度>=765px')
} else {
console.log('屏幕宽度<765px')
}
}
var mql = window.matchMedia('(min-width: 765px)')
// 因为响应函数只在状态有变化时才会执行,因此这里需要手动执行一次
mediaqueryresponse(mql)
// 添加响应函数
mql.addEventListener(mediaqueryresponse)
封装 matchMedia
js
const reactiveQuery = {
_subscribes: [], // 订阅的列表
_query: null,
_matchHandlers: [],
_screens: {}, // 响应式变化更新的值
_subUid: -1,
/*
订阅
*/
subscribe(query, callback) {
if (this._subscribes.length < 1) {
this._query = query
this.register()
}
const token = (++this._subUid).toString()
this._subscribes.push({
token,
callback,
})
callback(this._screens, null)
return token
},
/**
* 注册响应式查询
*/
register() {
if (this._query) {
Object.keys(this._query).forEach(key => {
const mediaQueryString = this._query[key]
if (!mediaQueryString) return
const mediaQueryListListener = mql => {
this.dispatch(
{
...this._screens,
[key]: mql.matches,
},
key
)
}
const mql = window.matchMedia(mediaQueryString)
mql.addEventListener(mediaQueryListListener)
this._matchHandlers[mediaQueryString] = {
mql,
key,
mediaQueryListListener,
}
mediaQueryListListener(mql)
})
}
},
/**
* 将最新的 screens 通知给 callback 函数
*/
dispatch(screens, screenDescribed) {
this._screens = screens
if (this._subscribes.length === 0) {
return false
}
this._subscribes.forEach(subscribe => {
subscribe.callback(screens, screenDescribed)
})
},
/*
取消对应的响应式订阅
*/
unsubscribe(token) {
this._subscribes = this._subscribes.filter(subscribe => subscribe.token !== token)
/**
在订阅为空时,清除所有事件响应器的绑定
*/
if (this._subscribes) {
this.unregister()
}
},
/*
清空所有的 mql.addListener 事件绑定
*/
unregister() {
Object.keys(this._query).forEach(key => {
const mediaQueryString = this._query[key]
if (!mediaQueryString) return
const matchHandle = this._matchHandlers[mediaQueryString]
if (matchHandle && matchHandle.mql && matchHandle.mediaQueryListListener) {
matchHandle.mql.removeEventListener(matchHandle.mediaQueryListListener)
}
})
},
}
使用
js
// 多条媒体查询语句
const query = {
xs: '(max-width:576px)',
sm: '(min-width:576px)',
md: '(min-width:768px)',
lg: '(min-width:992px)',
xl: '(min-width:1200px)',
xxl: '(min-width:1600px)',
}
reactiveQuery.subscribe(query, screen => {
// 视口的变化符合任何一条查询语句时
console.log('screen =>', screen)
})
响应操作系统主题变化
判断当前操作系统是否使用的是深色主题
js
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
if (prefersDarkScheme.matches) {
// 用户系统主题设置为 dark
}
响应操作系统主题变化
js
function onOperateSystemChange(prefersDarkScheme) {
if (prefersDarkScheme.matches) {
// 用户操作系统主题设置为 dark
} else {
// 用户操作系统主题设置为 非dark
}
}
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)')
// 添加响应
prefersDarkScheme.addEventListener(onOperateSystemChange)
// 删除响应
prefersDarkScheme.removeListener(onOperateSystemChange)