使用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;
    }
相关推荐
大怪v11 分钟前
前端:人工智能?我也会啊!来个花活,😎😎😎“自动驾驶”整起!
前端·javascript·算法
我是天龙_绍13 分钟前
vue3 props 如何写ts,进行类型标注
前端
叫我詹躲躲24 分钟前
n8n 自动化工作流平台完整部署
前端·langchain·领域驱动设计
遂心_2 小时前
为什么 '1'.toString() 可以调用?深入理解 JavaScript 包装对象机制
前端·javascript
IT_陈寒2 小时前
JavaScript 性能优化:5 个被低估的 V8 引擎技巧让你的代码快 200%
前端·人工智能·后端
岛风风2 小时前
关于手机的设备信息
前端
ReturnTrue8683 小时前
nginx性能优化之Gzip
前端
w_y_fan3 小时前
Flutter 滚动组件总结
前端·flutter
wuli金居哇3 小时前
我用 Turborepo 搭了个 Monorepo 脚手架,开发体验直接起飞!
前端
Asort3 小时前
JavaScript 从零开始(五):运算符和表达式——从零开始掌握算术、比较与逻辑运算
前端·javascript