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 处理,极大地提高了性能和流畅度。

相关推荐
WHOVENLY2 小时前
【javaScript】- 笔试题合集(长期更新,建议收藏,目前已更新至31题)
开发语言·前端·javascript
指尖跳动的光3 小时前
将多次提交合并成一次提交
前端·javascript
程序员码歌3 小时前
短思考第263天,每天复盘10分钟,胜过盲目努力一整年
android·前端·后端
oden3 小时前
1 小时速通!手把手教你从零搭建 Astro 博客并上线
前端
若梦plus3 小时前
JS之类型化数组
前端·javascript
若梦plus3 小时前
Canvas 深入解析:从基础到实战
前端·javascript
若梦plus3 小时前
Canvas渲染原理与浏览器图形管线
前端·javascript
C_心欲无痕3 小时前
vue3 - 依赖注入(provide/inject)组件跨层级通信的优雅方案
前端·javascript·vue.js
幺零九零零3 小时前
全栈程序员-前端第二节- vite是什么?
前端