使用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;
    }
相关推荐
百锦再6 小时前
Reactive编程入门:Project Reactor 深度指南
前端·javascript·python·react.js·django·前端框架·reactjs
莲华君6 小时前
React快速上手:从零到项目实战
前端·reactjs教程
百锦再6 小时前
React编程高级主题:测试代码
android·前端·javascript·react.js·前端框架·reactjs
易安说AI6 小时前
Ralph Loop 让Claude无止尽干活的牛马...
前端·后端
失忆爆表症8 小时前
05_UI 组件库集成指南:Shadcn/ui + Tailwind CSS v4
前端·css·ui
小迷糊的学习记录8 小时前
Vuex 与 pinia
前端·javascript·vue.js
发现一只大呆瓜8 小时前
前端性能优化:图片懒加载的三种手写方案
前端·javascript·面试
不爱吃糖的程序媛8 小时前
Flutter 与 OpenHarmony 通信:Flutter Channel 使用指南
前端·javascript·flutter
利刃大大8 小时前
【Vue】Element-Plus快速入门 && Form && Card && Table && Tree && Dialog && Menu
前端·javascript·vue.js·element-plus
NEXT069 小时前
AI 应用工程化实战:使用 LangChain.js 编排 DeepSeek 复杂工作流
前端·javascript·langchain