窗口大小变化导致页面卡顿?试试这几个办法

更新日期: 2026-04-24 阅读: 10 标签: 页面

很多人做响应式页面的时候,都会写这样一行代码:

window.addEventListener('resize', () => {
  // 做点什么
})

这个写法本身没毛病。但是页面一卡,问题就来了。


为什么会卡

窗口大小一变,resize事件会不停地触发。你鼠标拖一下窗口,一秒钟能触发几十次。

每次触发,你写的代码就会跑一遍。如果里面有操作DOM或者计算位置的代码,浏览器就得重新算样式、重新画页面。这就是重排。

重排一次还好,一秒来几十次,页面就抖得不行了。低配手机直接卡死。


一个会出问题的例子

window.addEventListener('resize', () => {
  const width = window.innerWidth
  if (width < 768) {
    document.body.classList.add('mobile')
  } else {
    document.body.classList.remove('mobile')
  }
})

这段代码看起来挺简单。但是窗口一拖动,这个函数一秒能跑几十次。每次都增删class,浏览器就得重新算样式。页面就会一卡一卡的。


用防抖来解决

防抖的意思:你一直动窗口,我就不干活。等你停下来了,我再干。

let timer = null

window.addEventListener('resize', () => {
  clearTimeout(timer)
  timer = setTimeout(() => {
    const width = window.innerWidth
    if (width < 768) {
      document.body.classList.add('mobile')
    } else {
      document.body.classList.remove('mobile')
    }
  }, 200)
})

你拖动窗口的时候,每次都会把上一个定时器清掉。等你停下来200毫秒之后,才真正执行代码。

好处:窗口怎么拖都不会卡。坏处:你要等到松手之后才会变化。


用节流让变化更顺滑

节流的意思:你一直动窗口,我每隔一段时间干一次活。不多干也不少干。

let canRun = true

window.addEventListener('resize', () => {
  if (!canRun) return
  canRun = false
  setTimeout(() => {
    const width = window.innerWidth
    if (width < 768) {
      document.body.classList.add('mobile')
    } else {
      document.body.classList.remove('mobile')
    }
    canRun = true
  }, 100)
})

不管你拖得多快,每100毫秒最多执行一次。页面不会卡,变化也不会太延迟。


防抖和节流怎么选

  • 如果你只关心窗口最后停在多大,用防抖。比如根据窗口宽度重新排版。

  • 如果你想在拖动过程中也要跟着变,但不要太频繁,用节流。比如跟着窗口大小调整某个元素的位置。

大部分响应式页面用防抖就够了。用户拖动窗口的时候不会一直盯着看,停下来再变也没问题。


一个更简单的办法:不用JS

很多需求其实根本不用监听resize。

比如你想在不同窗口大小下显示不一样的样式,用CSS媒体查询就行。

.mobile {
  display: none;
}

@media (max-width: 768px) {
  .desktop {
    display: none;
  }
  .mobile {
    display: block;
  }
}

这个完全不会卡。浏览器自己会处理,比JS快多了。

再比如你要算一个元素的位置,可以考虑用CSS的clamp()、vw、vh这些单位。很多动态布局都能直接用CSS搞定。


记得清理监听

在Vue或者React里面,加了resize监听,页面销毁的时候要记得拿掉。不然切到别的页面,监听还在,会出奇怪的问题。

Vue写法:

export default {
  mounted() {
    this.handleResize = () => {
      // 你的代码
    }
    window.addEventListener('resize', this.handleResize)
  },
  beforeUnmount() {
    window.removeEventListener('resize', this.handleResize)
  }
}

React写法:

useEffect(() => {
  const handleResize = () => {
    // 你的代码
  }
  window.addEventListener('resize', handleResize)
  return () => window.removeEventListener('resize', handleResize)
}, [])


高级办法:用ResizeObserver

窗口大小变了,你想知道某个元素的大小变成什么样了。这时候用resize监听窗口再算元素位置,很容易出问题。

ResizeObserver可以直接监听元素本身的大小变化。

const observer = new ResizeObserver((entries) => {
  const width = entries[0].contentRect.width
  if (width < 300) {
    // 做点事情
  }
})

observer.observe(document.querySelector('.box'))

这个比监听窗口好用。它只在元素大小真正变了的时候才触发,不会乱触发。性能也比resize好。

不过要注意,有些老浏览器不支持。你得看看你的用户用什么浏览器。可以用caniuse查一下兼容性。


总结

核心就这几条:

  • 能不用JS就不用JS,媒体查询优先

  • 非要用监听,加上防抖或者节流

  • 用完了记得清理监听

  • 监听元素大小用ResizeObserver,别用窗口resize再算

做到这几条,页面就不会因为窗口大小变化卡得跟幻灯片似的了。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13715

相关推荐

html页面实现返回上一页浏览位置

如果上一页是静态页面,可以用 history.go(-1)方法;页面采用了vue,页面每次加载都会去请求数据,用history.go(-1)方法返回上一页,上一页的页面因为重新请求数据,页面不会定位到上次浏览的位置;

js禁止页面回退的方法(使浏览器后退按钮失效)

这篇文章主要为大家详细介绍js禁止页面回退的方法(使浏览器后退按钮失效),具有一定的参考价值,感兴趣的小伙伴们可以参考一下

js监听用户进入和离开当前页面

VisibilityChange 事件;用于用户是否离开当前页面;页面的 visibilityState属性可能返回三种状态 prerender,visible 和 hidden ;监听 visibility change 事件;页面变为不可见时触发

Flutter页面跳转传参

路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity,在iOS中指一个ViewController。所谓路由管理,就是管理页面之间如何跳转,通常也可被称为导航管理

解决webapck多页面内存溢出

因为自己的项目是基于vue-cli3进行开发,所以这里只讨论这种情况下的解决办法 ,在进行多页面开发的时候,项目刚开始阶段,因为文件较少,所以代码编译速度还行,但是随着项目逐渐增大

vue进入页面时不在顶部,检测滚动返回顶部按钮

这里是本小白使用时遇到的问题及个人使用的方法可能并不完美。监测浏览器滚动条滚动事件及滚动距离,一般给window绑定监测事件就能获得window.pageYOffset滚动距离。

footer固定在页面底部的实现方法总结

footer固定在底部,footer保持在屏幕底部的四种方法实现:footer高度固定+绝对定位、footer高度固定+margin负值、footer高度任意+js、常用的纯css实现footer sticker

JS内嵌多个页面,页面之间如何更快捷的查找相关联的页面

假设parent为P页面,P页面有两个子页面,分别为B页面和C页面;B页面和C页面分别内嵌一个iframe,分别为:D页面和E页面,现在通过B页面的内嵌页面D的方法refreshEpage(eUrl)来加载内嵌页面E的内容.

网站设计如何为页面编写元描述

元描述是文本的片段,描述网页的内容,像百度这样的搜索引擎可选择在搜索结果中显示元描述,或绕过元描述显示想要或认为对特定搜索查询更重要的内容。但优化元描述是网站设计的重要因素,谈到网站设计时候

Flutter 之页面切换(基本路由)

一个应用程序通常由多个页面组成,而统一管理页面之间跳转的机制通常被称为路由管理或导航管理,在 Flutter 中,页面之间的跳转是通过 Route 和 Navigator 来管理的

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!