在不使用第三方插件的情况下用原生js监听屏幕尺寸变动的方法

原生JS监听屏幕尺寸变动的三种实现方案

导语

在现代响应式网页开发中,实时获取屏幕尺寸变化是一个常见需求。虽然有许多第三方库可以实现这一功能,但了解原生JavaScript的实现方式不仅能减少依赖,还能帮助我们深入理解浏览器的工作原理。本文将详细介绍三种原生JS监听屏幕尺寸的方法,并分析它们的适用场景。

核心概念解释

1. 视口(viewport)与屏幕尺寸

视口指的是浏览器窗口中实际显示网页内容的区域,不包括工具栏、滚动条等。屏幕尺寸变化通常指以下两种情况: - 浏览器窗口大小改变 - 设备方向改变(横竖屏切换)

2. 常用尺寸属性

  • window.innerWidth/innerHeight:包含滚动条的视口尺寸
  • window.outerWidth/outerHeight:整个浏览器窗口尺寸
  • screen.width/height:设备物理屏幕尺寸
  • document.documentElement.clientWidth/clientHeight:不包含滚动条的视口尺寸

三种监听方法

方法一:resize事件监听

window.addEventListener('resize', function() {
  console.log('窗口尺寸变化:', window.innerWidth, window.innerHeight);

  // 实际业务逻辑
  if (window.innerWidth < 768) {
    // 移动端布局处理
  } else {
    // 桌面端布局处理
  }
});

方法二:matchMedia API

const mediaQuery = window.matchMedia('(max-width: 600px)');

function handleTabletChange(e) {
  if (e.matches) {
    console.log('屏幕宽度小于600px');
  } else {
    console.log('屏幕宽度大于600px');
  }
}

// 初始检查
handleTabletChange(mediaQuery);

// 添加监听
mediaQuery.addListener(handleTabletChange);

// 移除监听(需要时)
// mediaQuery.removeListener(handleTabletChange);

方法三:requestAnimationFrame轮询(特殊场景)

let lastWidth = window.innerWidth;

function checkResize() {
  if (window.innerWidth !== lastWidth) {
    lastWidth = window.innerWidth;
    console.log('宽度变化:', lastWidth);
  }
  requestAnimationFrame(checkResize);
}

checkResize();

使用场景对比

方法 适用场景 不适用场景
resize事件 通用响应式布局 需要精确匹配特定断点
matchMedia 基于媒体查询的精确条件判断 需要连续变化值的情况
requestAnimationFrame 需要极高精度的特殊场景 普通响应式需求

优缺点分析

resize事件

优点: - 实现简单,兼容性好(支持到IE9) - 实时响应所有尺寸变化

缺点: - 触发频率高,可能导致性能问题 - 需要自行实现防抖逻辑

matchMedia API

优点: - 直接与CSS媒体查询协同工作 - 只在跨过阈值时触发,性能更好 - 可以同时监听多个条件

缺点: - IE10+支持(部分旧移动浏览器支持不完整) - 需要为每个断点单独设置监听

requestAnimationFrame轮询

优点: - 最高精度的控制 - 可以获取每一帧的变化

缺点: - 性能开销最大 - 实现复杂,大多数场景不需要

实战案例:响应式导航栏实现

<!DOCTYPE html>
<html>
<head>
  <style>
    .nav { display: flex; }
    .mobile-menu { display: none; }

    @media (max-width: 768px) {
      .nav { display: none; }
      .mobile-menu { display: block; }
    }
  </style>
</head>
<body>
  <div class="nav">桌面导航</div>
  <button class="mobile-menu">移动菜单</button>

  <script>
    // JS同步处理
    const mobileMenu = document.querySelector('.mobile-menu');
    const desktopNav = document.querySelector('.nav');

    function updateNavigation() {
      if (window.innerWidth <= 768) {
        desktopNav.style.display = 'none';
        mobileMenu.style.display = 'block';
      } else {
        desktopNav.style.display = 'flex';
        mobileMenu.style.display = 'none';
      }
    }

    // 初始状态
    updateNavigation();

    // 添加防抖的resize监听
    let resizeTimer;
    window.addEventListener('resize', () => {
      clearTimeout(resizeTimer);
      resizeTimer = setTimeout(updateNavigation, 100);
    });

    // 或者使用matchMedia
    const mql = window.matchMedia('(max-width: 768px)');
    mql.addListener(updateNavigation);
  </script>
</body>
</html>

性能优化建议

  1. 使用防抖(debounce)技术:避免resize事件频繁触发导致的性能问题
function debounce(func, wait) {
  let timeout;
  return function() {
    clearTimeout(timeout);
    timeout = setTimeout(func, wait);
  };
}

window.addEventListener('resize', debounce(() => {
  console.log('防抖处理后的resize事件');
}, 250));
  1. 合理选择监听方式:普通响应式布局优先使用matchMedia

  2. 及时移除监听器:在单页应用组件销毁时移除监听

// Vue组件示例
export default {
  mounted() {
    this.mql = window.matchMedia('(max-width: 768px)');
    this.mql.addListener(this.handleResize);
  },
  beforeDestroy() {
    this.mql.removeListener(this.handleResize);
  },
  methods: {
    handleResize(e) {
      // 处理逻辑
    }
  }
}

小结

原生JavaScript提供了多种监听屏幕尺寸变化的方法,各有其适用场景。对于大多数响应式布局需求,推荐结合使用resize事件(带防抖)和matchMedia API。理解这些原生实现方式不仅能减少项目依赖,还能帮助开发者更深入地掌握浏览器的工作原理,为处理更复杂的响应式场景打下坚实基础。

在实际项目中,应根据具体需求选择合适的方法,并注意性能优化和内存管理,特别是在单页应用中要及时清理事件监听器,避免内存泄漏。

posted @ 2025-07-04 15:45  富美  阅读(60)  评论(0)    收藏  举报