前端如何监听屏幕宽度的变化?

[复制链接]
发表于 2026-10-4 16:18:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

业务要在屏幕宽度变化时做点事——换布局、换图片、跑埋点。直觉做法是监听 resize,但它在移动端会误伤:用户上下滑一下,导航栏收起,可视高度变了,resize 就白白触发一次。这篇对比两种方案,并给出宽度判断的实现。

方法一:监听 resize 事件

最直接:

window.addEventListener('resize', () => {
  console.log(window.innerWidth, window.innerHeight);
});

PC 上拖窗口,宽高数值实时跟着变,够用。问题出在移动端。

移动浏览器把地址栏分成两种状态:页面在顶部时地址栏显示,往下滑后地址栏自动隐藏。地址栏一收,浏览器可视高度就变大了——高度变了,resize 照样触发。用户只是上下翻页,你的宽度相关逻辑却被白跑一次,轻则抖动,重则布局来回跳。

1.1 给 resize 加一道宽度过滤

最朴素的修法:初始化时用一个变量存下当前宽度,回调里比对,只有真变了才执行业务。

let lastWidth = window.innerWidth;

window.addEventListener('resize', () => {
  const currentWidth = window.innerWidth;
  if (currentWidth === lastWidth) return;   // 只有宽度变化才继续
  lastWidth = currentWidth;
  onWidthChange(currentWidth);
});

代价是得多维护一个 lastWidth 变量。接着看方法二,能把这个变量也省掉。

方法二:用 ResizeObserver 观察根元素

ResizeObserver 监听的是「元素边界尺寸」的变化,而不是整个视口。于是我们可以观察 document.documentElement(html 根元素)的边界,用它当作屏幕宽度的代理。

const resizeObserver = new ResizeObserver((entries) => {
  for (const entry of entries) {
    const { width, height } = entry.contentRect;
    console.log('宽度:', width, '高度:', height);
  }
});

resizeObserver.observe(document.documentElement);

每个被观察元素在回调里都带一个 contentRect 对象,里面有 width、height 等边界信息。关键点在于:

  • 当 html 元素本身没有 width / height / padding / margin 这些边界样式时,contentRect.width 就等于浏览器可视区宽度;
  • 移动端上下滑导致地址栏收起时,变的是高度、根元素宽度没动,Observe 就不会触发——正好把误触发挡在外面。

两种方案怎么选

维度resize 事件ResizeObserver
触发精度宽高任一变化都触发只观察目标元素边界
额外变量需要 lastWidth 记录旧值不需要
移动端误触发存在(地址栏收放)不存在
兼容性全平台现代浏览器(IE 不支持)
适用场景PC 后台、简单布局需要精确监听宽度的移动端页面

进阶:用 matchMedia 订阅断点

如果业务逻辑本质是「跨过某个断点就换布局」,用媒体查询订阅比数宽度更贴合语义:

const mq = window.matchMedia('(max-width: 768px)');

const onChange = (e) => {
  console.log(e.matches ? '进入移动端布局' : '回到桌面布局');
};

mq.addEventListener('change', onChange);   // 旧版 WebKit 只有 addListener,需按能力判断

注意旧版 WebKit 只支持 addListener,做兼容判断即可。

落地建议

  • 纯 PC 页面:resize 加宽度比对就够,代码最少。
  • 需要覆盖移动端:优先 ResizeObserver 观察根元素,避免地址栏抖动带来的假变化。
  • 逻辑本质是断点切换:用 matchMedia,可读性和可维护性都更好。
  • 无论哪种,回调用防抖(debounce 100–200ms)包一层,避免拖拽窗口时高频触发。

结论

监听窗口宽度变化有三档解法:resize 事件最简单但要自己存旧宽度过滤;ResizeObserver 观察根元素最干净,天然免疫移动端地址栏抖动;matchMedia 最适合断点型布局。同一段逻辑只有 PC 用的话,第一档就够;要上移动端,直接上第二档。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表