使用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;
    }
相关推荐
Boilermaker19921 小时前
【Java EE】SpringIoC
前端·数据库·spring
中微子1 小时前
JavaScript 防抖与节流:从原理到实践的完整指南
前端·javascript
天天向上10241 小时前
Vue 配置打包后可编辑的变量
前端·javascript·vue.js
芬兰y2 小时前
VUE 带有搜索功能的穿梭框(简单demo)
前端·javascript·vue.js
好果不榨汁2 小时前
qiankun 路由选择不同模式如何书写不同的配置
前端·vue.js
小蜜蜂dry2 小时前
Fetch 笔记
前端·javascript
拾光拾趣录2 小时前
列表分页中的快速翻页竞态问题
前端·javascript
小old弟2 小时前
vue3,你看setup设计详解,也是个人才
前端
Lefan2 小时前
一文了解什么是Dart
前端·flutter·dart
Patrick_Wilson2 小时前
青苔漫染待客迟
前端·设计模式·架构