前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你知道在 JavaScript 中也能使用媒体查询吗

你知道在 JavaScript 中也能使用媒体查询吗

作者头像
前端修罗场
发布2022-07-29 08:04:50
3.8K0
发布2022-07-29 08:04:50
举报
文章被收录于专栏:Web 技术

当你想到媒体查询时,你首先想到的是什么?也许在CSS文件中是这样的:

代码语言:javascript
复制
body {
  background-color: plum;
}


@media (min-width: 768px) {
  body {
    background-color: tomato;
  }
}

CSS媒体查询是任何响应式设计的核心成分。它们是将不同样式应用到不同上下文的好方法,无论它是基于视口大小、运动偏好、首选的配色方案、特定的交互,甚至是特定的设备,如打印机、电视和投影仪等。

但你知道我们对JavaScript也有媒体查询吗? 我们可能在JavaScript中并不经常看到它们,但在过去的几年里,我发现它们对于创建响应式插件(如滑块)很有帮助。例如,在某个分辨率下,您可能需要重新绘制和重新计算滑块项目。

在JavaScript中处理媒体查询与在CSS中处理媒体查询是非常不同的,尽管概念是相似的:匹配一些条件并应用一些东西。

Using matchMedia()

为了确定文档是否与JavaScript中的媒体查询字符串匹配,我们使用matchMedia()方法。尽管它是CSS对象模型视图模块规范的正式组成部分,但浏览器对它的支持可以追溯到ie10,全球覆盖率为98.6%

其用法几乎与CSS媒体查询相同。我们将媒体查询字符串传递给matchMedia(),然后检查.matches属性。

代码语言:javascript
复制
const mediaQuery = window.matchMedia('(min-width: 768px)')

定义的媒体查询将返回一个MediaQueryList对象。它是一个存储媒体查询信息的对象,我们需要的关键属性是.matches。这是一个只读布尔属性,如果文档匹配媒体查询则返回true。

代码语言:javascript
复制
// Create a media condition that targets viewports at least 768px wide
const mediaQuery = window.matchMedia('(min-width: 768px)')


// Check if the media query is true
if (mediaQuery.matches) {
  // Then trigger an alert
  alert('Media Query Matched!')
}

这是JavaScript中匹配媒体条件的基本用法。我们创建一个返回对象(MediaQueryList)的匹配条件(matchMedia()),对其进行检查(.matches),然后如果条件的计算结果为真,就执行操作。并不是完全不像CSS!

但还有更多。例如,如果我们改变窗口大小低于我们的目标窗口大小,没有任何更新方式与CSS直接开箱即用。这是因为.matches非常适合一次性的即时检查,但无法持续地检查更改。这意味着我们需要……

监听 changes 事件

MediaQueryList有一个addListener()(以及随后的removeListener())方法,它接受一个回调函数(由.onchange事件表示),该函数在媒体查询状态改变时被调用。换句话说,当条件发生变化时,我们可以触发额外的函数,允许我们“响应”更新后的条件。

代码语言:javascript
复制
// Create a condition that targets viewports at least 768px wide
const mediaQuery = window.matchMedia('(min-width: 768px)')


function handleTabletChange(e) {
  // Check if the media query is true
  if (e.matches) {
    // Then log the following message to the console
    console.log('Media Query Matched!')
  }
}


// Register event listener
mediaQuery.addListener(handleTabletChange)

// Initial check
handleTabletChange(mediaQuery)

matchMedia()MediaQueryList 的这两种组合使我们不仅能够匹配CSS提供的媒体条件,而且还能够积极响应更新的条件。

练习

代码语言:javascript
复制
<div class="info">Device Info:
代码语言:javascript
复制
const outputElement = document.getElementById("info");

const smallDevice = window.matchMedia("(min-width: 576px)");

smallDevice.addListener(handleDeviceChange);

function handleDeviceChange(e) {
  if (e.matches) outputElement.textContent = "Bigger Than Mobile";
  else outputElement.textContent = "Mobile";
}

// Run it initially
handleDeviceChange(smallDevice);

接着是 CSS:

代码语言:javascript
复制
.info {
  font-size: 18px;
  font-weight: bold;
}

/*
  CSS USED FOR THE TEMPLATE
*/

* {
  box-sizing: border-box;
}

body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  color: #252631;

  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  height: 100vh;
  background-color: #efefef;
}

.desc {
  max-width: 400px;
  opacity: 0.6;
  text-align: center;
  line-height: 1.6;
}

最终如下结果:

老方法存在的缺陷

出于上下文考虑——还有一点怀旧之情——我想介绍一下用JavaScript进行“媒体查询”的老方法(是的,这些引号在这里很重要)。最常见的方法是绑定一个检查window.innerWidthwindow.innerHeightresize 事件监听器

你仍然会看到这样的方式:

代码语言:javascript
复制
function checkMediaQuery() {
  // If the inner width of the window is greater then 768px
  if (window.innerWidth > 768) {
    // Then log this message to the console
    console.log('Media Query Matched!')
  }
}


// Add a listener for when the window resizes
window.addEventListener('resize', checkMediaQuery);

因为每次浏览器调整大小时都会调用resize事件,所以这是一个昂贵的操作!看看空页面对性能的影响,我们可以看到其中的差异。

查看区别的一种更简单的方法是借助控制台日志:

即使我们忽略了性能问题,resize 也是有限制的,因为它不允许我们为打印和方向等内容编写高级媒体查询。因此,虽然它确实模仿了“媒体查询”的行为,允许我们匹配视口宽度,但它不能匹配任何其他东西-我们知道,真正的媒体查询有这么多的能力。

结论

这就是JavaScript中的媒体查询!我们探索了matchMedia()如何允许我们定义媒体条件,并检查了MediaQueryList对象,该对象允许我们对这些条件进行一次性(.matches)和持久性(addListener())检查,以便我们可以通过调用函数来响应更改(.onchange)。

我们还看到了侦听窗口上的resize事件的“老”方法。尽管它仍然被广泛使用,并且是响应窗口大小变化的一种完全合法的方式。但是 innerWidth,无法对高级媒体条件执行检查。

为了完成本文,这里有一个用旧方法无法实现的有用示例。使用媒体查询,我将检查用户是否处于横向模式。这种方法在开发HTML5游戏时很常见,在移动设备上观看效果最好:

结论

这就是JavaScript中的媒体查询!我们探索了matchMedia()如何允许我们定义媒体条件,并检查了MediaQueryList对象,该对象允许我们对这些条件进行一次性(.matches)和持久性(addListener())检查,以便我们可以通过调用函数来响应更改(.onchange)。

我们还看到了侦听窗口上的resize事件的“老”方法。尽管它仍然被广泛使用,并且是响应窗口大小变化的一种完全合法的方式。但是 innerWidth,无法对高级媒体条件执行检查。

为了完成本文,这里有一个用旧方法无法实现的有用示例。使用媒体查询,我将检查用户是否处于横向模式。这种方法在开发HTML5游戏时很常见,在移动设备上观看效果最好。

HTML:

代码语言:javascript
复制
HTML SCSS JSResult Skip Results Iframe
EDIT ON
<div id="notice">
  <svg viewbox="0 0 512 512.001" xmlns="http://www.w3.org/2000/svg">
    <path d="m187.886719 7.566406h-170.5625c-5.300781 0-9.601563 4.296875-9.601563 9.601563v349.027343c0 5.304688 4.296875 9.601563 9.601563 9.601563h170.5625c5.300781 0 9.601562-4.296875 9.601562-9.601563v-349.027343c0-5.304688-4.300781-9.601563-9.601562-9.601563zm0 0" fill="#8ac2ff"></path>
    <path d="m136.492188 324.402344v170.5625c0 5.300781 4.296874 9.601562 9.601562 9.601562h349.027344c5.300781 0 9.601562-4.300781 9.601562-9.601562v-170.5625c0-5.300782-4.296875-9.601563-9.601562-9.601563h-349.027344c-5.304688 0-9.601562 4.300781-9.601562 9.601563zm0 0" fill="#8ac2ff"></path>
    <g fill="#54a0ff">
      <path d="m37.726562 366.195312v-349.027343c0-5.304688 4.296876-9.601563 9.597657-9.601563h-30c-5.304688 0-9.601563 4.296875-9.601563 9.601563v349.027343c0 5.304688 4.296875 9.601563 9.601563 9.601563h30c-5.300781 0-9.597657-4.296875-9.597657-9.601563zm0 0"></path>
      <path d="m166.492188 494.964844v-170.5625c0-5.300782 4.296874-9.601563 9.601562-9.601563h-30.003906c-5.300782 0-9.597656 4.296875-9.597656 9.601563v170.5625c0 5.300781 4.296874 9.601562 9.597656 9.601562h30.003906c-5.300781 0-9.601562-4.300781-9.601562-9.601562zm0 0"></path>
      <path d="m146.09375 314.800781c-5.304688 0-9.601562 4.300781-9.601562 9.601563v51.394531h51.394531c5.300781 0 9.601562-4.296875 9.601562-9.601563v-51.394531zm0 0"></path>
    </g>
    <path d="m166.492188 324.402344c0-5.300782 4.296874-9.601563 9.601562-9.601563h-30.003906c-5.300782 0-9.597656 4.296875-9.597656 9.601563v51.394531h30zm0 0" fill="#338def"></path>
    <path d="m463.453125 245.71875h-52.003906c-2.519531 0-3.777344 3.042969-2 4.824219l26.003906 26c1.101563 1.105469 2.890625 1.105469 3.996094 0l26-26c1.78125-1.78125.519531-4.824219-1.996094-4.824219zm0 0" fill="#e4eaf8"></path>
    <path d="m261.347656 46.351562-26 26c-1.105468 1.105469-1.105468 2.894532 0 4l26 26c1.78125 1.78125 4.824219.519532 4.824219-2v-52c0-2.519531-3.042969-3.777343-4.824219-2zm0 0" fill="#e4eaf8"></path>
    <path d="m431.683594 250.542969c-1.777344-1.78125-.519532-4.824219 2-4.824219h-22.234375c-2.519531 0-3.777344 3.042969-2 4.824219l26.003906 26c1.101563 1.105469 2.890625 1.105469 3.996094 0l9.117187-9.117188zm0 0" fill="#c7d2e5"></path>
    <path d="m257.582031 76.351562c-1.105469-1.105468-1.105469-2.894531 0-4l8.589844-8.589843v-15.410157c0-2.519531-3.046875-3.78125-4.824219-2l-26 26c-1.105468 1.105469-1.105468 2.894532 0 4l26 26c1.78125 1.78125 4.824219.519532 4.824219-2v-15.410156zm0 0" fill="#c7d2e5"></path>
    <path d="m404.410156 255.78125 26.003906 26c4.027344 4.027344 10.574219 4.027344 14.601563 0l26.003906-26c6.488281-6.492188 1.886719-17.628906-7.304687-17.628906h-18.640625c-3.5-92.816406-78.332031-167.679688-171.136719-171.222656v-18.644532c0-9.175781-11.128906-13.800781-17.628906-7.304687l-26 26.003906c-4.027344 4.023437-4.027344 10.578125 0 14.605469l26 25.996094c6.484375 6.488281 17.628906 1.910156 17.628906-7.300782v-18.34375c84.53125 3.527344 152.644531 71.667969 156.125 156.210938h-18.347656c-9.191406 0-13.792969 11.140625-7.304688 17.628906zm-145.476562-166.78125-14.714844-14.714844 14.714844-14.714844zm193.496094 164.152344-14.714844 14.71875-14.714844-14.71875zm0 0"></path>
    <path d="m494.898438 307.234375h-290.132813v-98.117187c0-4.144532-3.359375-7.5-7.5-7.5-4.144531 0-7.5 3.355468-7.5 7.5v98.117187h-43.894531c-9.429688 0-17.101563 7.671875-17.101563 17.101563v43.894531h-111.667969c-1.15625 0-2.101562-.941407-2.101562-2.097657v-349.03125c0-1.160156.945312-2.101562 2.101562-2.101562h170.5625c1.15625 0 2.101563.941406 2.101563 2.101562v157.015626c0 4.140624 3.355469 7.5 7.5 7.5s7.5-3.359376 7.5-7.5v-157.015626c0-9.429687-7.671875-17.101562-17.101563-17.101562h-170.5625c-9.429687 0-17.101562 7.671875-17.101562 17.101562v349.03125c0 9.429688 7.671875 17.101563 17.101562 17.101563h111.667969v111.664063c0 9.429687 7.671875 17.101562 17.101563 17.101562h155.195312c4.140625 0 7.5-3.355469 7.5-7.5s-3.359375-7.5-7.5-7.5h-155.195312c-1.160156 0-2.101563-.941406-2.101563-2.101562v-111.667969h43.894531c9.429688 0 17.101563-7.667969 17.101563-17.101563v-43.894531h290.132813c1.15625 0 2.101562.941406 2.101562 2.101563v170.5625c0 1.15625-.941406 2.101562-2.101562 2.101562h-158.832032c-4.144531 0-7.5 3.355469-7.5 7.5s3.355469 7.5 7.5 7.5h158.832032c9.429687 0 17.101562-7.671875 17.101562-17.101562v-170.5625c0-9.429688-7.671875-17.101563-17.101562-17.101563zm-305.132813 58.894531c0 1.160156-.945313 2.101563-2.101563 2.101563h-43.894531v-43.894531c0-1.15625.941407-2.101563 2.101563-2.101563h43.894531zm0 0"></path>
  </svg>
  <p>Please rotate the device.</p>
</div>
<div id="start">
  <mark>Start</mark>
</div>

CSS:

代码语言:javascript
复制
#notice {
  text-align: center;
}

a {
  color: #000;
}

footer {
  position: absolute;
  bottom: 10px;
  opacity: 0.4;
}

/*
  Template CSS
*/

* {
  box-sizing: border-box;
}

body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
  color: #252631;

  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  height: 100vh;
  background-color: #efefef;
}

svg {
  width: 54px;
  margin-bottom: 20px;
}

JS:

代码语言:javascript
复制
const landscapeMQ = window.matchMedia("(orientation: landscape)");

const noticeMessage = document.getElementById("notice");
const start = document.getElementById("start");

function handleTabletChange(e) {
  // Check if the media query is true
  if (e.matches) {
    noticeMessage.style.display = "none";
    start.style.display = "block";
  } else {
    noticeMessage.style.display = "block";
    start.style.display = "none";
  }
}

// Register event listener
landscapeMQ.addListener(handleTabletChange);
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端修罗场 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Using matchMedia()
  • 监听 changes 事件
    • 练习
    • 老方法存在的缺陷
    • 结论
    • 结论
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档