滚动动画(跑马灯动画)的几种实现方式

2023-05-16

在大屏可视化应用中,滚动动效(跑马灯效果)也是常见的一种数据展现方式,本章节针对字幕滚动和列表滚动效果做一个小小的总结,结合vue框架,具体展示效果如下,从左至右选型技术分别为:marquee标签、css3-animation动画属性、 css3-animation动画属性、Javascript实现滚动动画

 文字滚动实现功能描述:

  1. 文字无限滚动展示,支持鼠标悬浮暂停功能
  2. 文字滚动速度可控
  3. 支持接口数据动态渲染,如果数据变化,动画重新开始

列表滚动实现功能描述:

  1. 列表无限滚动展示、支持鼠标悬浮暂停功能
  2. 列表滚动速度可控
  3. 支持接口数据动态渲染,数据变化,动画重新开始
  4. 支持鼠标滚动操作、可上滑至动画开始处或下滑至动画结束处
  5. 每页展示列表项数量可控

功能实现分析:

 常规动画类的实现效果,无非有三种方式:其一是借助原生html标签-marquee实现滚动效果;其二是通过css3相关动画属性实现动画效果;其三是使用javascript结合定时器,通过轮询实现相关属性动态变化的动画效果;当然每一种实现方式都有各自的优缺点,大家可以根据需要进行技术选型,本章针对相关实现原理进行简单阐述。

这里使用静态数据模拟接口数据,具体数据格式如下

// data.js
export let datas1 = `Vue 的响应式原理是核心是通过 ES5 的保护对象的 Object.defindeProperty中的
访问器属性中的 get和 set方法,data 中声明的属性都被添加了访问器属性,当读取 data 中的数据时自动调用 
get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 
Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新
虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到
真实 DOM 树上`

export let datas2 = `《意见》明确,保障性租赁住房主要解决符合条件的新市民、青年人等群体的住房困难问题,
以建筑面积不超过70平方米的小户型为主,租金低于同地段同品质市场租赁住房租金;由政府给予政策支持,充分发挥
市场机制作用,引导多主体投资、多渠道供给,主要利用存量土地和房屋建设,适当利用新供应国有建设用地建设。
城市人民政府要坚持供需匹配,科学确定“十四五”保障性租赁住房建设目标和政策措施,制定年度建设计划,
并向社会公布;加强对保障性租赁住房建设、出租和运营管理的全过程监督,强化工程质量安全监管。
城市人民政府对本地区发展保障性租赁住房负主体责任,省级人民政府负总责。`

export let datas3 = [
    {
        content: "内容一",
        bgColor: "#08a6e9",
    },
    {
        content: "内容二",
        bgColor: "#22d4c8",
    },
    {
        content: "内容三",
        bgColor: "#ffa06a",
    },
    {
        content: "内容四",
        bgColor: "#0f96f0",
    },
    {
        content: "内容五",
        bgColor: "#ffa66a",
    }
];

export let datas4 = [
    {
        content: "content-1",
        bgColor: "#08a6e9",
    },
    {
        content: "content-2",
        bgColor: "#22d4c8",
    },
    {
        content: "content-3",
        bgColor: "#ffa06a",
    },
    {
        content: "content-4",
        bgColor: "#0f96f0",
    },
    {
        content: "content-5",
        bgColor: "#ffa66a",
    }
];

一、marquee标签实现文字滚动动画(对应图片第一个)

1.在组件中使用

<!-- 基于原生html-marquee标签实现滚动效果 -->
<template>
  <div class="container">
    <marquee
      scrollamount="4"
      hspace="0"
      vspace="0"
      behavior="scroll"
      direction="up"
    >
      <p class="content">{{ content }}</p>
    </marquee>
  </div>
</template>
<script>
import { datas1 } from "./data";
export default {
  data() {
    return {
      content: datas1,
    };
  },
};
</script>
<style scoped>
.container {
  width: 300px;
  height: 300px;
  padding: 10px;
  outline: 1px dashed #ccc;
  overflow: hidden;
}
.content {
  font-size: 14px;
  line-height: 30px;
  text-indent: 2em;
}
</style>

2.marquee标签的实现方式非常简单、只需要添加对应的属性即可,针对开发者非常友好。但是它是一个过时的标签、另外无法实现无缝滚动效果,难以应对复杂的需求场景、因此在项目中应用场景并不多。

二、css3-animation实现文字滚动效果(对应图片第二个)

1.首先封装一个文字滚动组件,代码如下

<template>
  <div class="font-wrap" ref="topbox">
    <div :class="['font-list', dynamicCls]" :style="dynamicSty">
      <div ref="fontbox" v-text="content"></div>
      <div v-if="doubleData" v-text="content"></div>
    </div>
  </div>
</template>
<script>
export default {
  name: "FontScrollIndex",
  props: {
    content: {
      default: "",
    },
    pageDuration: {
      default: 6,
    },
  },
  data() {
    return {
      doubleData: false, // 是否需要双份数据
      fontBox: null, // 文字容器
      topBox: null, // 文字父级容器
      countFlag: 0, // 切换clss类标识符
      dynamicCls: "", // 动态class类,切换使用解决数据更新后动画不重新开始问题
      dynamicSty: {},
    };
  },
  mounted() {
    this.fontBox = this.$refs.fontbox;
    this.topBox = this.$refs.topbox;
    this.$nextTick(() => {
      this.calcHeight();
    });
  },
  methods: {
    calcHeight() {
      // 判断内容是否超出容器,如果超出容器、追加一份数据
      if (this.fontBox.offsetHeight > this.topBox.offsetHeight) {
        this.doubleData = true;
        this.countFlag += 1;
        // 切换动画类名
        this.dynamicCls = `scroll-cls${this.countFlag % 2}`;
        // 动态计算动画时长
        this.dynamicSty = {
          animationDuration: `${
            (this.fontBox.offsetHeight / this.topBox.offsetHeight) *
            this.pageDuration
          }s`,
        };
      } else {
        this.doubleData = false;
        this.dynamicCls = "";
        this.dynamicSty = {
          animationDuration: "0s",
        };
      }
    },
  },
  watch: {
    // 监听内容变化
    content(val) {
      this.$nextTick(() => {
        this.calcHeight();
      });
    },
  },
};
</script>
<style scoped>
.font-wrap {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
.scroll-cls0 {
  animation: translateY1 8s 0.5s linear infinite;
}
.scroll-cls1 {
  animation: translateY2 8s 0.5s linear infinite;
}
.font-list:hover {
  animation-play-state: paused;
}
@keyframes translateY1 {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-50%);
  }
}
@keyframes translateY2 {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-50%);
  }
}
</style>

 2.组件调用

<!-- 基于CSS3-animation动画属性实现文字滚动效果-仅用于字幕滚动 -->
<template>
  <div class="container-wrapper">
    <!-- 滚动组件,如果需要给滚动组件文字添加样式,添加到container的div上即可 -->
    <div class="container">
      <!-- 组件接受两个参数,content:滚动的文字内容;pageDuration滚动一页需要的时间 -->
      <font-scroll :content="content" :pageDuration="10"></font-scroll>
    </div>
  </div>
</template>
<script>
import { datas1, datas2 } from "./data";
import FontScroll from "./FontScroll";
export default {
  components: { FontScroll },
  name: "FontScrollIndex",
  data() {
    return {
      content: datas1,
    };
  },
  mounted() {
    // 模拟数据发生变化
    setTimeout(() => {
      this.content = datas2;
    }, 10000);
  },
};
</script>
<style scoped>
.container-wrapper {
  display: flex;
  justify-content: space-around;
  width: 300px;
  height: 300px;
}
.container {
  width: 300px;
  height: 300px;
  padding: 10px;
  margin: 0 auto;
  outline: 1px dashed #ccc;
  font-size: 14px;
  line-height: 30px;
  text-indent: 2em;
}
</style>

3.使用animation实现稍微有点复杂,比如:数据列表数量时多时少,这就需要动态计算动画时长;其次实现无缝滚动需要动态计算内容高度,判断是否需要追加数据,双份数据或单份数据;另外当列表数据变化时列表动画重新开始也需要做特殊处理。但优势也非常明显,无需开发者关注动画性能问题、动画效果流畅、全程css控制仅需少量的javascript进行控制,改实现方式在实际开发中应用较多,推荐使用。

三、css3-animation实现列表滚动效果(对应图片第三个)

1.组件封装

<template>
  <div class="page-box">
    <!--
      为实现无缝滚动效果,需注意事项:
      1.内容容器(item-list)不留margin和padding
      2.数据列表项-li也不留margin和padding、紧挨排列
      3.将需要展示的内容放至class为item-content的标签下
    -->
    <ul :class="['item-list', dynamicCls]" :style="dynamicSty">
      <li v-for="(item, index) in itemList" :key="index">
        <div class="item-content" :style="{ 'background-color': item.bgColor }">
          {{ item.content }}
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
import { datas3, datas4 } from "./data";
export default {
  name: "PageScroll",
  data() {
    return {
      singleDuration: 2, // 每一条滚动多久
      pageSize: 4, // 每页显示几个
      itemList: [], // 渲染数据列表
      dbData: datas3, // 模拟接口数据
      countFlag: 0, // 切换clss类标识符
      dynamicCls: "", // 动态class类,切换使用解决数据更新后动画不重新开始问题
      dynamicSty: {}, // 动态样式
    };
  },
  mounted() {
    this.calcAttr();
    // 模拟接口数据更新
    setTimeout(() => {
      this.dbData = datas4;
      this.calcAttr();
    }, 10000);
  },
  methods: {
    // 动态计算动画相关属性
    calcAttr() {
      let length = this.dbData.length;
      // 如果大于pageSize,则启用动画
      if (length > this.pageSize) {
        this.countFlag += 1;
        this.itemList = [...this.dbData, ...this.dbData];
        // 切换动画类名
        this.dynamicCls = `scroll-box${this.countFlag % 2}`;
        // 动态设置样式-开启动画
        this.dynamicSty = {
          height: (100 / this.pageSize) * length * 2 + "%", // 动态计算容器高度
          "animation-iteration-count": "infinite",
          "animation-duration": `${length * this.singleDuration}s`,
        };
      } else {
        this.itemList = this.dbData;
        // 动态设置样式-关闭动画
        this.dynamicSty = {
          height: (100 / this.pageSize) * length + "%", // 动态计算容器高度
          "animation-iteration-count": "0",
          "animation-duration": "0s",
        };
      }
    },
  },
};
</script>
<style scoped>
.page-box {
  width: 300px;
  height: 300px;
  overflow: hidden;
}
.item-list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  animation-timing-function: linear;
}

.item-list:hover {
  animation-play-state: paused;
}

.item-list > li {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.item-content {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  color: #fff;
  width: 80%;
  height: 80%;
  border-radius: 6px;
}
.scroll-box0 {
  animation: box-move0 8s 0.5s linear infinite;
}
.scroll-box1 {
  animation: box-move1 8s 0.5s linear infinite;
}
@keyframes box-move0 {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-50%);
  }
}
@keyframes box-move1 {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(-50%);
  }
}
</style>

 2.列表滚动-css3实现方式和css3-文字版实现原理大致一样,具体实现方式可查看以上代码和备注文字描述。该方式是通过列表容器位移实现的,适应于大部分的场景。如果有特殊需求,比如:可通过鼠标滑动列表,就需要通过javascript控制了。

四、Javascript实现滚动效果(对应图片第四个)

1.该实现方案是在“案例三”的基础上增加了鼠标滚轮滑动操作,通过动态改变scrollTop属性实现滚动展示,相比css控制,这种控制方式具有更强的可塑性

2.代码如下:

<!-- 基于javaScript scrollTop实现滚动效果 -->
<template>
  <div class="container" @mouseenter="stopScroll" @mouseleave="startScroll">
    <!--
      为实现无缝滚动效果,需注意事项:
      1.内容容器(container-wrapper)不留margin和padding
      2.数据列表项-li也不留margin和padding、紧挨排列
      3.将需要展示的内容放至class为item-content的标签下
    -->
    <ul class="container-wrapper" ref="box">
      <li v-for="(item, index) in itemList" :key="index">
        <div class="item-content" :style="{ 'background-color': item.bgColor }">
          {{ item.content }}
        </div>
      </li>
    </ul>
  </div>
</template>
<script>
import { datas3, datas4 } from "./data";
export default {
  data() {
    return {
      box: null, // 内容容器
      Timer: null, // 记录定时器id
      dbData: datas3, // 模拟接口数据
      itemList: [], // 渲染数据列表
      pageSize: 4, // 每页显示几个
    };
  },
  mounted() {
    this.box = this.$refs.box;
    this.calcAttr();
    // 模拟接口数据更新
    setTimeout(() => {
      this.dbData = datas4;
      this.calcAttr();
    }, 10000);
  },
  beforeDestroy() {
    // 组件销毁前务必关闭动画,释放资源
    this.stopScroll();
  },
  methods: {
    calcAttr() {
      // 关闭滚动动画
      this.stopScroll();
      // 动画重新开始
      this.box.parentNode.scrollTop = 0;
      // 根据数据长度及每页展示数量,动态计算容器高度
      let length = this.dbData.length;
      if (length > this.pageSize) {
        // 超过一页,需要给与双份数据
        this.box.style.height = `${(100 / this.pageSize) * length * 2}%`;
        this.itemList = [...this.dbData, ...this.dbData];
      } else {
        // 不超过一页,单份数据
        this.box.style.height = `${(100 / this.pageSize) * length}%`;
        this.itemList = this.dbData;
      }
      // 务必等待dom重新渲染之后执行滚动动画
      this.$nextTick(() => {
        this.startScroll();
      });
    },
    startScroll() {
      this.stopScroll();
      // 判断是否滚动了一半,如果超过一半,拉回去重新开始
      if (this.box.offsetHeight > this.box.parentNode.offsetHeight) {
        this.box.parentNode.scrollTop++;
        if (this.box.parentNode.scrollTop >= this.box.offsetHeight / 2) {
          this.box.parentNode.scrollTop = 0;
        }
        // 定时滚动
        this.Timer = requestAnimationFrame(this.startScroll);
      }
    },
    stopScroll() {
      if (this.Timer) {
        cancelAnimationFrame(this.Timer);
        this.Timer = null;
      }
    },
  },
};
</script>
<style scoped>
.container {
  width: 300px;
  height: 300px;
  outline: 1px solid #ccc;
  overflow: auto;
}
.container-wrapper {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}
.container-wrapper > li {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
.item-content {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 14px;
  color: #fff;
  width: 80%;
  height: 80%;
  border-radius: 6px;
}
</style>

总结:每一种实现方案都有自己的使用场景,大家可以结合实际需求进行技术选型,掌握了滚动动画实现的原理,就可以在实际开发中得心应手。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

滚动动画(跑马灯动画)的几种实现方式 的相关文章

随机推荐

  • 基于Paddle实现实例分割

    百度的Paddle这几年发展十分迅速 xff0c 而且文档十分齐全 xff0c 涉及到机器视觉的多个应用领域 xff0c 感觉还是非常牛的 xff0c 各种backbone xff0c 损失函数 数据增强手段以及NMS等 xff0c 整体感
  • 机器学习笔记: 时间序列 分解 STL

    1 前言 STL Seasonal and Trend decomposition using Loess 是以LOSS 作为平滑方式的时间序列分解 LOSS可以参考机器学习笔记 xff1a 局部加权回归 LOESS UQI LIUWJ的博
  • C++11 auto遍历

    C 43 43 11这次的更新带来了令很多C 43 43 程序员期待已久的for range循环 xff0c 每次看到javascript xff0c lua里的for range xff0c 心想要是C 43 43 能有多好 xff0c
  • C++ 文件的读写(fin && fout)

    如何让键盘输入字符保存在 txt文件中 如何让我们自己在键盘上输入的字符不仅仅在屏幕上显示 xff0c 而且还能保存在特定路径的文件中 xff0c 这让简单枯燥的控制台命令程序变得略有趣 首先 xff0c 先看看cin和cout对象 xff
  • 基本矩阵、本质矩阵和单应矩阵

    两幅视图存在两个关系 xff1a 第一种 xff0c 通过对极几何一幅图像上的点可以确定另外一幅图像上的一条直线 xff1b 另外一种 xff0c 通过上一种映射 xff0c 一幅图像上的点可以确定另外一幅图像上的一个点 xff0c 这个点
  • 矩阵零空间

    矩阵A的零空间就Ax 61 0的解的集合 零空间的求法 xff1a 对矩阵A进行消元求得主变量和自由变量 xff1b 给自由变量赋值得到特解 xff1b 对特解进行线性组合得到零空间 假设矩阵如下 xff1a 对矩阵A进行高斯消元得到上三角
  • VIO学习总结

    VIO xff08 visual inertial odometry xff09 即视觉惯性里程计 xff0c 有时也叫视觉惯性系统 xff08 VINS xff0c visual inertial system xff09 xff0c 是
  • 单应性(Homography)变换

    我们已经得到了像素坐标系和世界坐标系下的坐标映射关系 xff1a 其中 xff0c u v表示像素坐标系中的坐标 xff0c s表示尺度因子 xff0c fx fy u0 v0 xff08 由于制造误差产生的两个坐标轴偏斜参数 xff0c
  • senmantic slam mapping

    basicStructure hpp common h 定义一些常用的结构体 以及各种可能用到的头文件 xff0c 放在一起方便include 相机内参模型 增加了畸变参数 xff0c common headers h各种可能用到的头文件
  • Ubuntu 20.04 VNC 安装与设置

    原链接 VNC是一个远程桌面协议 按照本文的说明进行操作可以实现用VNC对Ubuntu 20 04进行远程控制 一般的VNC安装方式在主机没有插显示器的时候是无法使用的 下面的操作可以在主机有显示器和没有显示器时都能够正常工作 首先安装x1
  • opencv中类型转换问题

    记录一下最近困惑我的问题 方便以后查阅 在学习立体匹配算法中BM算法时 xff0c 出现在了关于类型转换的问题 xff1a disp convertTo disp8u CV 8U 255 numberOfDisparities 16 不知道
  • 最大似然估计MLE与贝叶斯估计

    最大似然估计 Maximum Likehood Estimation MLE 最大似然估计的核心思想是 xff1a 找到参数 的一个估计值 xff0c 使得当前样本出现的可能性最大 用当年博主老板的一句话来说就是 xff1a 谁大像谁 xf
  • 大疆Livox_mid 40雷达初体验

    为了解决无人车上镭神雷达FOV小而导致的车前3m内无法看到锥形桶问题 东家给公司邮寄了一台大疆的mid40雷达 不得不说 颜值真的高 光看颜值 就甩镭神几条街 昨天重新配置镭神的激光雷达 官方给的配置软件 真的是 用的我心碎啊 算了 不提了
  • 地铁供电系统的构成

    地铁供电系统一般划分为以下几部分 xff1a 外部电源 xff1b 主变电所 xff1b 牵引供电系统 xff1b 动力照明系统和杂散电流腐蚀防护系统 xff1b 电力监控系统 外部电源地铁供电系统的外部电源就是地铁供电系统主变电所供电的外
  • C++ Vector常用函数

    C 43 43 Vector常用函数 begin 函数 原型 xff1a iterator begin const iterator begin 功能 xff1a 返回一个当前vector容器中起始元素的迭代器 end 函数 原型 xff1
  • STM32使用ADC获取内部温度传感器数据输出(直接读取/DMA两种方式实现)

    STM32使用ADC获取内部温度传感器数据输出 xff08 直接读取 DMA两种方式实现 xff09 前言一 内部温度传感器的使用 xff1f 二 代码操作讲解1 直接读取2 DMA处理 总结 前言 STM32F1系列 xff08 本代码基
  • fp32/fp64精度,4/8字节16进制转float/double十进制

    1 IEEE 754 32位单精度浮点数 xff08 4字节 xff09 1 1 32位单精度浮点数 其中 xff0c 32位16进制数包括1位符号位 SIGN xff0c 8位指数位 EXPONENT 和 23位尾数位 MANTISSA
  • SVG绘制圆环进度条

    在我们的大屏可视化项目中 xff0c 经常会用到各种各样的图表 与传统的表格展示 枯燥的文字阐述相比 xff0c 图表展示则使用户看起来更加直观 数据的展示则更加一目了然 本文基于svg绘图技术结合前端技术栈vue xff0c 以工作中常用
  • Canvas绘制地图

    在我们的大屏可视化项目中 xff0c 地图数据可视化是最常见功能 地图数据可视化目前的实现方案有很多 xff0c 其中最具有代表性的莫过于使用echarts xff0c 引入一个js文件 xff0c 再加上一些简单的配置 xff0c 这样一
  • 滚动动画(跑马灯动画)的几种实现方式

    在大屏可视化应用中 xff0c 滚动动效 xff08 跑马灯效果 xff09 也是常见的一种数据展现方式 xff0c 本章节针对字幕滚动和列表滚动效果做一个小小的总结 xff0c 结合vue框架 xff0c 具体展示效果如下 xff0c 从