CSS Keyframes 实现 Vue 无缝无限轮播

🚀 纯 CSS Keyframes 实现 Vue 无缝无限轮播组件(跑马灯效果)

实现一个基于 Vue 和纯 CSS 实现的双向无限轮播(跑马灯)组件的使用,支持多行,并且鼠标悬停自动暂停!


🌟 组件核心

  • 性能: 使用 CSS transformanimation
  • 无缝: 通过巧妙的数据复制-50% 滚动技巧实现完美无缝衔接。
  • 交互: 鼠标悬停(hover)时,自动暂停滚动。

💻 完整代码:MarqueeLoop.vue

1. Vue Template 和 Script

代码段

ini 复制代码
<template>
  <div class="marquee-container">
    <div class="marquee-row">
      <div class="marquee-track">
        <div class="logo-card" v-for="(item, index) in row1" :key="'r1-'+index" @click="openLink(item.url)">
          <img :src="item.imgUrl" fit="fill" />
          <span v-if="!item.logo">{{ item.name }}</span>
        </div>
        <div class="logo-card" v-for="(item, index) in row1" :key="'r1-dup-'+index"
             @click="openLink(item.url)">
          <img :src="item.imgUrl" fit="fill" />
          <span v-if="!item.logo">{{ item.name }}</span>
        </div>
      </div>
    </div>

    <div class="marquee-row">
      <div class="marquee-track-right">
        <div class="logo-card" v-for="(item, index) in row2" :key="'r2-'+index" @click="openLink(item.url)">
          <img :src="item.imgUrl" fit="fill" />
          <span v-if="!item.logo">{{ item.name }}</span>
        </div>
        <div class="logo-card" v-for="(item, index) in row2" :key="'r2-dup-'+index"
             @click="openLink(item.url)">
          <img :src="item.imgUrl" fit="fill" />
          <span v-if="!item.logo">{{ item.name }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

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

const row1 = ref([
  { name: 'Vue', imgUrl: 'https://cdn.example.com/vue.png', url: 'https://vuejs.org/' },
  { name: 'React', imgUrl: 'https://cdn.example.com/react.png', url: 'https://react.dev/' },
  { name: 'Node', imgUrl: '', logo: false, url: 'https://nodejs.org/' },
]);

const row2 = ref([
  { name: 'Google', imgUrl: 'https://cdn.example.com/google.png', url: 'https://www.google.com/' },
  { name: 'Apple', imgUrl: 'https://cdn.example.com/apple.png', url: 'https://www.apple.com/' },
]);

const openLink = (url) => {
  if (url) {
    window.open(url, '_blank');
  }
};
</script>

2. CSS 样式和 Keyframes

CSS

xml 复制代码
<style scoped>
.marquee-container {
    width: 100%;
    background-color: #f5f7fa;
    padding: 20px 0;
    overflow: hidden; 
}

.marquee-row {
    display: flex;
    margin-bottom: 20px;
    overflow: hidden;
    width: 100%;
}

/* --- 滚动轨道定义 --- */
.marquee-track,
.marquee-track-right {
    display: flex;
    width: max-content; 
    flex-shrink: 0;
}

.marquee-track {
    animation: scroll-left 30s linear infinite; /* 向左滚动 */
}

.marquee-track-right {
    animation: scroll-right 30s linear infinite; /* 向右滚动 */
}

/* 交互:鼠标悬停暂停动画 */
.marquee-track:hover,
.marquee-track-right:hover {
    animation-play-state: paused;
}

/* --- 卡片样式 (可自定义) --- */
.logo-card {
    width: 350px; /* 调整卡片宽度 */
    height: 200px; /* 调整卡片高度 */
    background: #ffffff;
    margin: 0 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    flex-shrink: 0;
    cursor: pointer;
    transition: transform 0.2s;
}

.logo-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.logo-card img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

/* --- 动画关键帧 --- */

/* 1. 向左滚动:0% -> -50% */
@keyframes scroll-left {
    0% {
        transform: translateX(0);
    }
    100% {
        transform: translateX(-50%);
    }
}

/* 2. 向右滚动:-50% -> 0% */
@keyframes scroll-right {
    0% {
        transform: translateX(-50%);
    }
    100% {
        transform: translateX(0);
    }
}
</style>

💡 无缝滚动原理揭秘

  1. 数据翻倍: 在 模板中,使用 v-for 将数据 (row1row2) 渲染了两遍

  2. width: max-content 确保两个列表被强制排在一行,且容器总宽度是单个列表宽度的两倍。

  3. 关键的 -50%

    • 向左: 动画从 translateX(0) 移动到 translateX(-50%)。当第一组数据完全移出屏幕时(即移动了 50% 的总宽度),动画瞬间重置回 0,此时屏幕上显示的是第二组数据的起点,完美对接,实现视觉上的无限循环。
    • 向右: 动画从 translateX(-50%)(即第二组数据的起点)移动到 translateX(0)(即第一组数据的起点),实现反向循环。

通过这种方式,我们避免了使用 JavaScript 计算或操作 DOM,将动画交给 CSS 处理,极大地提高了性能和流畅度。

相关推荐
小扎仙森43 分钟前
html引导页
前端·html
小飞侠在吗1 小时前
vue toRefs 与 toRef
前端·javascript·vue.js
csuzhucong1 小时前
斜转魔方、斜转扭曲魔方
前端·c++·算法
燃烧的土豆1 小时前
100¥ 实现的React项目 Keep-Alive 缓存控件
前端·react.js·ai编程
半生过往1 小时前
前端运行PHP 快速上手 使用 PHPStudy Pro 详细搭建与使用指南
开发语言·前端·php
zlpzlpzyd1 小时前
ecmascript中Promise和async/await的区别
开发语言·前端·ecmascript
streaker3031 小时前
从零实现一个“类微信”表情输入组件
前端·vue.js·element
小明记账簿_微信小程序2 小时前
js、node.js获取指定文件下的内容
前端
小明记账簿_微信小程序2 小时前
h5中弹框出现后禁止页面滚动
前端