使用js使页面元素匀速横向滚动,如何能减少性能消耗

背景

在HikCentral Professional 行业(智能巡检、食堂消费、月台管理)V1.1项目和HikCentral Professional ADDON V2.0项目中,月台的排队叫号业务以及教育的接送大屏业务都涉及到大屏页面,大屏都只做数据展示,无法进行触点击悬浮等交互,页面数据超长时,无法按寻常方式进行省略展示。以下均以教育接送大屏业务作为示例。

方案

页面文本一旦涉及超长,均采取横向轮播滚动的形式进行处理。

效果图

初始实现

  1. 滚动元素A设置绝对定位,容器元素B设置相对定位
  2. 获取元素A和元素B的长度,分别为widthA和widthB
  3. 若widthA小于等于widthB,元素A则正常展示不做滚动,步骤结束
  4. 若widthA大于widthB,使用定时器setInterval定时修改元素A的left定位,使A向左移动,此时left为负数
  5. 若元素A向左的定位位移大于等于widthB,则将元素A的left定位为+widthB,表现为元素A从右边重新出现
  6. 重复步骤4-5
js 复制代码
 // 横向滚动
    getDomWidthAndMove(textClass, isChangeScreen) {
      let textDom = document.getElementById(textClass);
      if (!textDom) {
        return;
      }
      let textLength = textDom.offsetWidth;
      let boxWidth = textDom.parentNode.offsetWidth;
      let leftStyle = parseInt(textDom.style.left.split('px')[0], 10);
      if (isChangeScreen) {
        textDom.style.left = '0px';
        return;
      }
      if (textLength > boxWidth) {
        if (!leftStyle && leftStyle !== 0) {
          textDom.style.left = '0px';
        } else if (Math.abs(leftStyle) >= textLength) {
          textDom.style.left = `${boxWidth }px`;
        } else {
          textDom.style.left = `${leftStyle - 1 }px`;
        }
      } else {
        if (leftStyle && leftStyle !== 0) {
          textDom.style.left = '0px';
        }
      }
      // 回收
      textDom = null;
    }

存在问题

  1. 大屏性能较低,长时间运行带有横向滚动效果的页面,会导致白屏
  2. 使用定时器时,动画效果不太流畅,存在卡顿问题

优化分析

  1. 通常,使用JavaScript的setInterval或递归setTimeout来不断修改元素的transform或left属性是比较常见的方法,但这些方法可能会导致重排(reflow)和重绘(repaint),尤其是在频繁操作DOM时。
  2. 如何优化JavaScript的实现呢?首先,减少重排和重绘是关键。使用transform的translateX属性会比修改left或marginLeft更高效,因为transform可以利用GPU加速,不会触发布局重排。另外,使用requestAnimationFrame代替setInterval或setTimeout可以确保动画与浏览器的刷新率同步,减少不必要的帧绘制,提高流畅度。
  3. 还需要考虑将滚动元素提升为合成层,这可以通过CSS的will-change属性或transform3d来实现,这样浏览器会将该元素单独处理,减少重新绘制的区域。此外,避免在滚动过程中进行复杂的DOM操作或样式计算,这些都会增加性能开销。
  4. 总结可能的优化点:使用requestAnimationFrame、transform进行位移、提升为合成层、避免强制同步布局、减少DOM操作等。

优化策略

  • 使用CSS transform代替传统定位属性:transform的translateX操作会触发GPU加速,且不会引起布局重排

  • 使用requestAnimationFrame替代setInterval:与浏览器刷新率同步,避免过度绘制

  • 优化DOM结构:确保滚动元素形成独立的合成层,减少重绘区域

  • 使用will-change属性预提示浏览器优化

  • 避免强制同步布局:不要在动画循环中读取布局属性

优化实现

  1. 滚动元素A设置transform动画,容器元素B设置超长隐藏
  2. 获取元素A和元素B的长度,分别为widthA和widthB
  3. 若widthA小于等于widthB,元素A则正常展示不做滚动,步骤结束
  4. 若widthA大于widthB,使用请求帧requestAnimationFrame定时修改元素A的translateX,使A向左移动,此时translateX为负数
  5. 若元素A向左的定位位移大于等于widthB,则将元素A的translateX为widthB,表现为元素A从右边重新出现
  6. 重复步骤4-5
js 复制代码
 // 横向滚动
    getDomWidthAndMove(textClass, isChangeScreen) {
      let textDom = document.getElementById(textClass);
      if (!textDom) {
        return;
      }
      let textLength = textDom.offsetWidth;
      let boxWidth = textDom.parentNode.offsetWidth;
      let translateX = parseInt(textDom.style.transform?.replace(/[^\d-]/g, '') || 0, 10);
      if (isChangeScreen) {
        textDom.style.transform = 'translateX(0)';
        return;
      }
      if (textLength > boxWidth) {
        if (Math.abs(translateX) >= textLength) {
          textDom.style.transform = `translateX(${boxWidth}px)`;
        } else {
          textDom.style.transform = `translateX(${translateX - 1}px)`;
        }
      } else {
        textDom.style.transform = 'translateX(0)';
      }
      // 回收
      textDom = null;
    }
相关推荐
水银嘻嘻28 分钟前
08 web 自动化之 PO 设计模式详解
前端·自动化
Zero1017132 小时前
【详解pnpm、npm、yarn区别】
前端·react.js·前端框架
&白帝&3 小时前
vue右键显示菜单
前端·javascript·vue.js
Wannaer3 小时前
从 Vue3 回望 Vue2:事件总线的前世今生
前端·javascript·vue.js
羽球知道3 小时前
在Spark搭建YARN
前端·javascript·ajax
光影少年3 小时前
vue中,created和mounted两个钩子之间调用时差值受什么影响
前端·javascript·vue.js
青苔猿猿3 小时前
node版本.node版本、npm版本和pnpm版本对应
前端·npm·node.js·pnpm
一只码代码的章鱼4 小时前
Spring的 @Validate注解详细分析
前端·spring boot·算法
zimoyin4 小时前
Kotlin 协程实战:实现异步值加载委托,对值进行异步懒初始化
java·前端·kotlin
程序员与背包客_CoderZ6 小时前
Node.js异步编程——Callback回调函数实现
前端·javascript·node.js·web