vue实现数据栏无缝滚动实现方式-demo

news2024/12/28 23:24:22

效果 

 方式一

通过实现两个item 进行循环

<!--
 * @Author: Jackie
 * @Date: 2023-08-16 21:27:42
 * @LastEditTime: 2023-08-16 21:41:51
 * @LastEditors: Jackie
 * @Description: scroll  水平滚动 - 效果基本满足需求
 * @FilePath: /vue3-swiper-demo/src/components/scroll/Scroll12.vue
 * @version: 
-->
<template>
  <div class="ticker-container">
    <div class="ticker-viewer">
      <div class="ticker-scroll">
        <div
          class="ticker-scroll-item"
          :key="index"
          v-for="(item, index) in items"
        >
          <span v-if="item">{{ item }} ${{ item }}</span>
        </div>
      </div>
      <div class="ticker-scroll">
        <div
          class="ticker-scroll-item"
          :key="index"
          v-for="(item, index) in items"
        >
          <span v-if="item">{{ item }} ${{ item }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const items = ref(Array.from({ length: 26 }, (_, index) => index + 1));
</script>

<style lang="scss" scoped>
.ticker-container {
  align-items: center;
  background: linear-gradient(90deg, #86eef1, #bcff2f 138.82%);
  display: flex;
  height: 50px;
  white-space: nowrap;
  width: 100%;
  .ticker-viewer {
    align-items: center;
    cursor: pointer;
    display: flex;
    height: 100%;
    overflow: hidden;
    position: relative;
    width: 100%;
    .ticker-scroll {
      animation-delay: 8s;
      opacity: 0;

      animation: tickerScroll 240s linear infinite normal;
      transform: translateX(0);

      transition: all linear;
      will-change: transform, opacity;
      .ticker-scroll-item {
        display: inline-block;
        font-size: 18px;
        line-height: 22px;
        color: #fff;
        padding: 0 24px;
      }
    }
  }
}

@keyframes tickerScroll {
  0% {
    opacity: 1;
    transform: translateX(0);
  }

  to {
    opacity: 1;
    transform: translateX(-100%);
  }
}

@keyframes positionScroll {
  0% {
    transform: translateX(3.33333333%);
  }

  to {
    transform: translateX(0);
  }
}
</style>

方式二

通过实现两个item 进行循环

<!--
 * @Author: Jackie
 * @Date: 2023-08-16 21:02:42
 * @LastEditTime: 2023-08-16 21:42:04
 * @LastEditors: Jackie
 * @Description: 过渡 - 通过两次滚动实现 flex  - 效果基本满足需求
 * @FilePath: /vue3-swiper-demo/src/components/scroll/Scroll11.vue
 * @version: 
-->
<template>
  <div class="scroll">
    <div class="price-band-group" ref="group">
      <div
        class="price-band-item DIN-medium"
        :key="index"
        v-for="(item, index) in items"
      >
        <span v-if="item">{{ item }} ${{ item }}</span>
      </div>
    </div>
    <div class="price-band-group" ref="group">
      <div
        class="price-band-item DIN-medium"
        :key="index"
        v-for="(item, index) in items"
      >
        <span v-if="item">{{ item }} ${{ item }}</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const scroller = ref(null);
const group = ref(null);
const timerId = ref(null);
const items = ref(Array.from({ length: 26 }, (_, index) => index + 1));
</script>

<style lang="scss" scoped>
.scroll {
  display: flex;
  overflow: hidden;
  width: 100%;
  height: 48px;
  background: linear-gradient(90deg, #31daff 0.47%, #316bff 100%);
  padding: 13px 0;
  box-sizing: border-box;
  overflow: auto;
  .price-band-group {
    display: flex;
    white-space: nowrap;
    /* animation: index_loop 100s linear infinite normal;
    animation-delay: 0.5s; */
    animation: tickerScroll 240s linear infinite normal;
    transform: translateX(0);
    .price-band-item {
      display: inline-block;
      font-size: 18px;
      line-height: 22px;
      color: #fff;
      padding: 0 24px;
    }
  }
  &::-webkit-scrollbar {
    display: none;
  }
}

@keyframes index_loop {
  0% {
    transform: translateZ(0);
  }

  to {
    transform: translate3d(-50%, 0, 0);
  }
}

@keyframes tickerScroll {
  0% {
    opacity: 1;
    transform: translateX(0);
  }

  to {
    opacity: 1;
    transform: translateX(-100%);
  }
}
</style>

方式三

通过尾部填充重复数据实现

<template>
  <div class="scroll" ref="scroller" :style="style">
    <div class="price-band-group" v-if="items.length">
      <div
        class="price-band-item DIN-medium"
        v-for="(item, index) in itemsWithTail"
        :key="index"
      >
        <span v-if="item !== null"> {{ item }} ${{ item }} </span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';
const scroller = ref(null);
const timerId = ref(null);
const items = ref(Array.from({ length: 12 }, (_, index) => index + 1));
const pauseAnimate = () => {
  timerId.value && clearInterval(timerId.value);
  timerId.value = null;
};
const playAnimate = () => {
  pauseAnimate();
  const maxScrollLeft = scroller.value.scrollWidth - scroller.value.clientWidth;
  console.log(maxScrollLeft);
  timerId.value = setInterval(() => {
    if (scroller.value.scrollLeft >= maxScrollLeft) {
      scroller.value.scrollLeft -= maxScrollLeft;
    }
    scroller.value.scrollLeft += 1;
  }, 33);
};

const itemsWithTail = computed(
  () =>
    items.value.length >= 10 ? items.value.concat(items.value) : items.value
  //   items.value.concat(items.value.slice(0, 4))
);

onMounted(() => {
  setTimeout(() => {
    scroller.value.scrollLeft = 0;
    playAnimate();
  }, 100);
});

onUnmounted(() => {
  pauseAnimate();
});
</script>

<style lang="scss" scoped>
.scroll {
  width: 100%;
  height: 48px;
  background: linear-gradient(90deg, #31daff 0.47%, #316bff 100%);
  padding: 13px 0;
  box-sizing: border-box;
  overflow: hidden;
  transition: scroll-left 1s ease-in-out; /* 添加过渡效果 */
  .price-band-group {
    display: inline-block;
    white-space: nowrap;
    .price-band-item {
      display: inline-block;
      font-size: 18px;
      line-height: 22px;
      color: #fff;
      padding: 0 24px;
    }
  }
  &::-webkit-scrollbar {
    display: none;
  }
}
</style>

方式四

滚动到头后,直接归0

<template>
  <div class="scroll" ref="scroller" :style="style">
    <div class="price-band-group">
      <div class="price-band-item DIN-medium" v-for="item in items" :key="item">
        <span v-if="item"> {{ item }} ${{ item }} </span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const scroller = ref(null);
const timerId = ref(null);
const scrollLeftEnd = ref(false);
const items = ref(Array.from({ length: 22 }, (_, index) => index + 1));
const pauseAnimate = () => {
  timerId.value && clearInterval(timerId.value);
  timerId.value = null;
};
const playAnimate = () => {
  pauseAnimate();
  const maxScrollLeft = scroller.value.scrollWidth - scroller.value.clientWidth;
  console.log(maxScrollLeft);
  timerId.value = setInterval(() => {
    if (scroller.value.scrollLeft >= maxScrollLeft) {
      scroller.value.scrollLeft -= maxScrollLeft;
    }
    scroller.value.scrollLeft += 1;
  }, 33);
};

onMounted(() => {
  console.log(111);
  // 必须在100ms后进行,否则计算不准确
  setTimeout(() => {
    scroller.value.scrollLeft = 0;
    playAnimate();
  }, 100);
});
onUnmounted(() => {
  pauseAnimate();
});
</script>

<style lang="scss" scoped>
.scroll {
  width: 100%;
  height: 48px;
  background: linear-gradient(90deg, #31daff 0.47%, #316bff 100%);
  padding: 13px 0;
  box-sizing: border-box;
  overflow: auto;
  .price-band-group {
    display: inline-block;
    white-space: nowrap;
    .price-band-item {
      display: inline-block;
      font-size: 18px;
      line-height: 22px;
      color: #fff;
      padding: 0 24px;
    }
  }
  &::-webkit-scrollbar {
    display: none;
  }
}
</style>

方式五

来回滚动方式

<template>
  <div class="scroll" ref="scroller" :style="style">
    <div class="price-band-group">
      <div class="price-band-item DIN-medium" v-for="item in 26" :key="item">
        <span v-if="item"> {{ item.item }} ${{ item }} </span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const scroller = ref(null);
const timerId = ref(null);
const scrollLeftEnd = ref(false);
const pauseAnimate = () => {
  timerId.value && clearInterval(timerId.value);
  timerId.value = null;
};
const playAnimate = () => {
  pauseAnimate();
  const maxScrollLeft = scroller.value.scrollWidth - scroller.value.clientWidth;
  console.log(maxScrollLeft);
  timerId.value = setInterval(() => {
    if (scroller.value.scrollLeft >= maxScrollLeft - 1) {
      scrollLeftEnd.value = true;
    }
    if (scroller.value.scrollLeft <= 1) {
      scrollLeftEnd.value = false;
    }
    if (scrollLeftEnd.value) {
      scroller.value.scrollTo({
        top: 0,
        left: (scroller.value.scrollLeft -= 1),
        behavior: 'smooth'
      }); //scrollLeft -= 1;
    } else {
      scroller.value.scrollTo({
        top: 0,
        left: (scroller.value.scrollLeft += 1),
        behavior: 'smooth'
      }); //scrollLeft += 1;
    }
  }, 33);
};

onMounted(() => {
  console.log(111);
  // 必须在100ms后进行,否则计算不准确
  setTimeout(() => {
    scroller.value.scrollLeft = 0;
    playAnimate();
  }, 100);
});
onUnmounted(() => {
  pauseAnimate();
});
</script>

<style lang="scss" scoped>
.scroll {
  width: 100%;
  height: 48px;
  background: linear-gradient(90deg, #31daff 0.47%, #316bff 100%);
  padding: 13px 0;
  box-sizing: border-box;
  overflow: auto;
  .price-band-group {
    display: inline-block;
    white-space: nowrap;
    .price-band-item {
      display: inline-block;
      font-size: 18px;
      line-height: 22px;
      color: #fff;
      padding: 0 24px;
    }
  }
  &::-webkit-scrollbar {
    display: none;
  }
}
</style>

方式六

scroll滚动 - 循环滚动,不超出不滚动

<!--
 * @Author: Jackie
 * @Date: 2023-08-17 10:55:21
 * @LastEditTime: 2023-08-17 11:39:17
 * @LastEditors: Jackie
 * @Description: scroll滚动 - 循环滚动,不超出不滚动
 * @FilePath: /vue3-swiper-demo/src/components/scroll/Scroll13.vue
 * @version: 
-->
<template>
  <div class="ticker-container">
    <div class="ticker-viewer" ref="scrollWiewer">
      <div
        class="ticker-scroll"
        ref="scrollContainer"
        :class="{ 'scroll-animation': !shouldScroll }"
        :style="{ animationDuration: animationDuration }"
      >
        <div
          class="ticker-scroll-item"
          :key="index"
          v-for="(item, index) in items"
        >
          <span v-if="item">{{ item }} ${{ item }}</span>
        </div>
      </div>
      <div
        class="ticker-scroll"
        v-if="shouldScroll"
        :style="{ animationDuration: animationDuration }"
      >
        <div
          class="ticker-scroll-item"
          :key="index"
          v-for="(item, index) in items"
        >
          <span v-if="item">{{ item }} ${{ item }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';

const items = ref(Array.from({ length: 26 }, (_, index) => index + 1));
const shouldScroll = ref(false);
const scrollContainer = ref(null);
const scrollWiewer = ref(null);

// 计算动画持续时间
const animationDuration = computed(() => {
  const itemCount = items.value.length;
  // 根据元素数量调整倍数
  const durationMultiplier = 2; // 调整这个值以适应您的需求
  return `${itemCount * durationMultiplier}s`;
});

onMounted(() => {
  const wiewerWidth = scrollWiewer.value.offsetWidth;

  const containerWidth = scrollContainer.value.offsetWidth;
  const contentWidth = scrollContainer.value.scrollWidth;

  console.log(containerWidth, wiewerWidth, containerWidth > wiewerWidth);
  shouldScroll.value = containerWidth > wiewerWidth;
});

onUnmounted(() => {
  shouldScroll.value = false;
});
</script>

<style lang="scss" scoped>
.ticker-container {
  align-items: center;
  background: linear-gradient(90deg, #86eef1, #bcff2f 138.82%);
  display: flex;
  height: 50px;
  white-space: nowrap;
  width: 100%;

  .ticker-viewer {
    align-items: center;
    cursor: pointer;
    display: flex;
    height: 100%;
    overflow: hidden;
    position: relative;
    width: 100%;

    .ticker-scroll {
      /* opacity: 0; */

      transition: all linear;
      will-change: transform, opacity;

      /* animation: tickerScroll 20s linear infinite normal; */
      animation-name: tickerScroll;
      animation-timing-function: linear;
      animation-iteration-count: infinite;
      animation-direction: normal;
      transform: translateX(0);
      /* 没有超出不滚动 */
      &.scroll-animation {
        animation: none; // stopScroll 1s linear 1 normal;
        transform: translateX(0);
      }

      .ticker-scroll-item {
        display: inline-block;
        font-size: 18px;
        line-height: 22px;
        color: #fff;
        padding: 0 24px;
      }
    }
  }
}

@keyframes tickerScroll {
  0% {
    opacity: 1;
    transform: translateX(0);
  }

  to {
    opacity: 1;
    transform: translateX(-100%);
  }
}

@keyframes stopScroll {
  0% {
    transform: translateX(0);
  }
}

@keyframes positionScroll {
  0% {
    transform: translateX(3.33333333%);
  }

  to {
    transform: translateX(0);
  }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开始场景的制作+气泡特效的添加

3D场景或2D场景的切换 1.新建项目时选择3D项目或2D项目 2.如下图操作&#xff1a; 开始前的固有流程 按照如下步骤进行操作&#xff0c;于步骤3中更改Company Name等属性&#xff1a; 本案例分辨率可以如下设置&#xff0c;有能力者可根据需要自行调整&#xff1a; 场景制作…

python是什么语言写的

Python是一种计算机程序设计语言。是一种面向对象的动态类型语言。现今Python语言很火&#xff0c;可有人提问&#xff0c;这么火的语言它的底层又是什么语言编写的呢&#xff1f; python是C语言编写的&#xff0c;它有很多包也是用C语言写的。 所以说&#xff0c;C语言还是很…

算法.图论-并查集

文章目录 1. 并查集介绍2. 并查集的实现2.1 实现逻辑2.2 isSameSet方法2.3 union方法(小挂大优化)2.4 find方法(路径压缩优化) 3. 并查集模板4. 并查集习题4.1 情侣牵手4.2 相似字符串组 1. 并查集介绍 定义&#xff1a; 并查集是一种树型的数据结构&#xff0c;用于处理一些不…

(学习记录)使用 STM32CubeMX——配置时钟(入门)

使用STM32CubeMX配置STM32F103C8T6时钟部分 选择芯片 ①&#xff1a;选择MCU型号 ①&#xff1a;这里使用英文输入法&#xff0c;输入你想要的芯片型号&#xff0c;我这里采用STM32F103C8T6 ②&#xff1a;这里能看到搜索后出来的芯片具体型号&#xff0c;选择匹配度最高的一个…

类和对象(2)(重点)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 类的默认成员函数 概念概述 默认成员函数就是用户没有显式实现&#xff0c;编译器会自…

【CSS in Depth 2 精译_034】5.4 Grid 网格布局的显式网格与隐式网格(下)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

ACM MM24 | Hi3D: 3D生成领域再突破!新视角生成和高分辨率生成双SOTA(复旦智象等)

文章链接&#xff1a;https://arxiv.org/pdf/2409.07452 Github 链接&#xff1a;https://github.com/yanghb22-fdu/Hi3D-Official 亮点直击 本文提出了高分辨率图像到3D模型&#xff08;Hi3D&#xff09;&#xff0c;这是一种基于视频扩散的新范式&#xff0c;将单个图像重新定…

计算机毕业设计python+spark知识图谱房价预测系统 房源推荐系统 房源数据分析 房源可视化 房源大数据大屏 大数据毕业设计 机器学习

《PythonSpark知识图谱房价预测系统》开题报告 一、研究背景与意义 随着城市化进程的加速和房地产市场的不断发展&#xff0c;房价成为影响人们生活质量的重要因素之一。准确预测房价不仅有助于政府制定科学的房地产政策&#xff0c;还能为开发商提供市场参考&#xff0c;同时…

NLP-transformer学习:(7)evaluate实践

NLP-transformer学习&#xff1a;&#xff08;7&#xff09;evaluate 使用方法 打好基础&#xff0c;为了后面学习走得更远。 本章节是单独的 NLP-transformer学习 章节&#xff0c;主要实践了evaluate。同时&#xff0c;最近将学习代码传到&#xff1a;https://github.com/Mex…

c++类与对象一

C类与对象(一) 面向对象初步认识 在c语言中&#xff0c;编程是面向过程编程&#xff0c;注重求解问题列出过程&#xff0c;然后调用函数求解问题。 在日常生活中。我们经常会遇到面向过程的问题 手洗衣服就是面向过程 而C是基于面向对象的。关注的是对象&#xff0c;把事情…

SpringSecurity -- 入门使用

文章目录 什么是 SpringSesurity &#xff1f;细节使用方法 什么是 SpringSesurity &#xff1f; 在我们的开发中&#xff0c;安全还是有些必要的 用 拦截器 和 过滤器 写代码还是比较麻烦。 SpringSecurity 是 SpringBoot 的底层安全默认选型。一般我们需要认证和授权&#xf…

【Finetune】(三)、transformers之P-Tuning微调

文章目录 0、P-Tuning基本原理1、代码实战1.1、导包1.2、加载数据集1.3、数据集预处理1.4、创建模型1.5、P-tuning*1.5.1、配置文件1.5.2、创建模型 1.6、配置训练参数1.7、创建训练器1.8、模型训练1.9、模型推理 0、P-Tuning基本原理 P-Tuning的基本思想是在prompt-tuning的基…

Spring Boot管理用户数据

目录 学习目标前言Thymeleaf 模板JSON 数据步骤 1: 创建 Spring Boot 项目使用 Spring Initializr 创建项目使用 IDE 创建项目 步骤 2: 添加依赖步骤 3: 创建 Controller步骤 4: 新建index页面步骤 5: 运行应用程序 表单提交步骤 1: 添加 Thymeleaf 依赖在 Maven 中添加依赖 步…

Vue3.3新特性defineModel

defineModel的使用: defineModel选项可以帮我们省去很多麻烦 不仅需要上述操作&#xff0c;还需要进行一定的配置&#xff1a; 在vite.config.js中进行配置 defineModel是一个宏&#xff0c;所以不需要从vue中import导入&#xff0c;直接使用就可以了。这个宏可以用来声明一个…

Java之线程篇六

目录 CAS CAS伪代码 CAS的应用 实现原子类 实现自旋锁 CAS的ABA问题 ABA问题导致BUG的例子 相关面试题 synchronized原理 synchronized特性 加锁过程 相关面试题 Callable 相关面试题 JUC的常见类 ReentrantLock ReentrantLock 和 synchronized 的区别: 原…

Android 新增目录怎么加入git

工作中会遇到android系统源码系统增加第三方功能支持&#xff0c;需要增加目录&#xff0c;那么这个目录怎么提交到服务器上去呢&#xff1f;接下来我们就看下这个问题的解决 一服务器创建仓库 一个新的目录增加到仓库中&#xff0c;需要仓库有对应的仓库地址&#xff0c;这个让…

小记编程语言浮点精度问题

注意&#xff1a; 本文内容于 2024-09-15 20:21:12 创建&#xff0c;可能不会在此平台上进行更新。如果您希望查看最新版本或更多相关内容&#xff0c;请访问原文地址&#xff1a;小记编程语言浮点精度问题。感谢您的关注与支持&#xff01; 浮点数在计算机中不能精确表示所有…

docker启动mysql未读取my.cnf配置文件问题

描述 在做mysql主从复制配置两台mysql时&#xff0c;从节点的my.cnf配置为&#xff1a; [mysqld] datadir /usr/local/mysql/slave1/data character-set-server utf8 lower-case-table-names 1 # 主从复制-从机配置# 从服务器唯一 ID server-id 2 # 启用中继日志 relay-l…

【小沐学CAD】3ds Max常见操作汇总

文章目录 1、简介2、二次开发2.1 C 和 3ds Max C SDK2.2 NET 和 3ds Max .NET API2.3 3ds Max 中的 Python 脚本2.4 3ds Max 中的 MAXScript 脚本 3、快捷键3.1 3Dmax键快捷键命令——按字母排序3.2 3dmax快捷键命令——数字键3.3 3dmax功能键快捷键命令3.4 3Dmax常用快捷键——…

对网页聊天项目进行性能测试, 使用JMeter对于基于WebSocket开发的webChat项目的聊天功能进行测试

登录功能 包括接口的设置和csv文件配置 ​​​​​​ 这里csv文件就是使用xlsx保存数据, 然后在浏览器找个网址转成csv文件 注册功能 这里因为需要每次注册的账号不能相同, 所以用了时间函数来当用户名, 保证尽可能的给正确的注册数据, 时间函数使用方法如下 这里输入分钟, 秒…