基于 Naive UI 的 Vue 3 跑马灯组件实现与优化

组件背景与来源

本文介绍的跑马灯组件是基于 Naive UI的优秀设计理念提炼整理而成。Naive UI 是一个完整的 Vue 3 组件库,以其优雅的设计和出色的性能著称。我们在其 Marquee 组件的基础上进行了精简和优化,特别加强了鼠标交互体验。

组件概述

这是一个高性能的 Vue 3 跑马灯组件,适用于新闻滚动、公告展示、时间轴等场景。组件具有以下核心特性:

  • ♾️ 无限循环滚动​ - 基于 CSS 动画实现无缝滚动

  • 📏 自适应宽度​ - 自动根据容器和内容尺寸调整

  • ⚡ 性能优化​ - 使用 CSS 变换和硬件加速

  • 🖱️ 交互控制​ - 鼠标悬停暂停/继续

  • 🎚️ 可调速度​ - 支持动态调整滚动速度

核心实现原理

1. 响应式尺寸检测机制

组件使用 ResizeObserver实时监测尺寸变化,确保在各种屏幕尺寸下都能完美展示:

// 创建 ResizeObserver 实例
const resizeObserver = ref<ResizeObserver | null>(null);

function handleContentResize(entries: ResizeObserverEntry[]) {
  for (const entry of entries) {
    if (entry.target === contentElRef.value) {
      contentWidthRef.value = entry.contentRect.width;
    } else if (entry.target === containerElRef.value) {
      containerWidthRef.value = entry.contentRect.width;
    }
  }
}

2. 动态内容重复算法

为了确保无缝循环,组件动态计算需要重复的内容组数:

const repeatCountInOneGroupRef = computed(() => {
  const { value: contentWidth } = contentWidthRef;
  const { value: containerWidth } = containerWidthRef;
  if (contentWidth === -1 || containerWidth === -1) return 1;
  return Math.ceil(containerWidthRef.value / contentWidth);
});

3. 动画参数计算

基于内容宽度和速度参数计算动画时长:

const durationRef = computed(() => {
  const { value: contentWidth } = contentWidthRef;
  if (contentWidth === -1) return 0;
  return (contentWidth * repeatCountInOneGroupRef.value) / props.speed;
});

鼠标悬停交互优化

实现原理

我们在原生 Naive UI 组件的基础上增强了鼠标交互功能,让用户体验更加友好:

// 鼠标悬停事件处理 - 新增功能
function handleMouseEnter() {
  playStateRef.value = "paused";
}

// 鼠标离开事件处理 - 新增功能
function handleMouseLeave() {
  playStateRef.value = "running";
}

交互设计思路

  1. 悬停暂停:当用户鼠标悬停时,动画暂停,方便阅读内容

  2. 离开继续:鼠标移出后,动画从暂停位置继续播放

  3. 平滑过渡:通过 CSS 的 animation-play-state实现平滑的暂停/继续效果

完整组件代码解析

模板结构

<template>
  <div
    class="marquee"
    ref="containerElRef"
    :style="animationCssVarsRef"
    @mouseenter="handleMouseEnter"    <!-- 新增鼠标事件 -->
    @mouseleave="handleMouseLeave"    <!-- 新增鼠标事件 -->
  >
    <!-- 第一组内容 -->
    <div
      class="marquee__group"
      @animationiteration="handleAnimationIteration"
      ref="contentElRef"
    >
      <slot />
    </div>
    <!-- 第二组内容用于无缝衔接 -->
    <div class="marquee__group">
      <slot />
    </div>
  </div>
</template>

样式实现

.marquee {
  overflow: hidden;
  display: flex;
  width: 100%;

  &__group {
    flex: 0 0 auto;
    min-width: var(--n-min-width);
    z-index: 1;
    display: flex;
    flex-direction: row;
    align-items: center;
    
    /* 核心动画定义 */
    animation: n-marquee var(--n-duration) linear var(--n-delay) infinite;
    animation-play-state: var(--n-play);  /* 支持暂停/继续 */
    
    @keyframes n-marquee {
      from {
        transform: translateX(0);
      }
      to {
        transform: translateX(-100%);
      }
    }
  }
}

动画控制逻辑

const animationCssVarsRef = computed(() => {
  return {
    "--n-play": playStateRef.value,        // 控制播放状态
    "--n-duration": `${durationRef.value}s`, // 动画时长
    "--n-delay": "0s",
    "--n-iteration-count": "infinite",
    "--n-min-width": "auto",
  };
});

使用示例

<template>
  <div class="demo-container">
    <marquee :speed="50">
      <div class="content-wrapper">
        <div class="content-item" v-for="item in items" :key="item.id">
          <span class="item-text">{{ item.text }}</span>
        </div>
      </div>
    </marquee>
  </div>
</template>

CSS 动画优势

  • 硬件加速:使用 transform属性触发 GPU 加速

  • 流畅性:避免 JavaScript 直接操作 DOM 导致的布局抖动

  • 低功耗:浏览器可以对 CSS 动画进行优化

与其他方案的对比

特性

本组件

传统 JS 实现

纯 CSS 动画

性能

✅ 优秀(硬件加速)

❌ 一般

✅ 优秀

可控性

✅ 完全可控

✅ 高度可控

❌ 有限

无缝循环

✅ 完美支持

✅ 支持

❌ 困难

交互体验

✅ 悬停暂停

✅ 可定制

❌ 有限

兼容性

✅ Vue 3 生态

✅ 广泛

✅ 广泛

实际应用建议

1. 速度参数调优

<!-- 不同场景的速度建议 --> 
<marquee :speed="80"> 
<!-- 快速展示,适合标语 --> 
<marquee :speed="50"> 
<!-- 中等速度,通用场景 --> 
<marquee :speed="30"> 
<!-- 慢速,适合阅读性内容 -->

2. 响应式适配

// 移动端适配
@media (max-width: 768px) {
  .marquee {
    &__group {
      animation-duration: calc(var(--n-duration) * 1.2); // 移动端稍慢
    }
  }
}

3. 内容长度优化

  • 确保单个内容块宽度适中(建议 200-400px)

  • 避免内容过长影响滚动效果

  • 考虑移动端的触摸交互体验

总结与展望

本组件在 Naive UI 原有设计的基础上,通过以下方面进行了优化:

  1. 交互增强:新增鼠标悬停暂停功能,提升用户体验

  2. 代码精简:去除复杂配置,保持核心功能的简洁性

  3. 性能保持:继承原有的 CSS 动画优化方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值