---
url: /guide/motion.md
---
# 动效

Evoke UI 的动效主张是「**克制而有生命**」：位移用平滑曲线、浮现用 spring 弹性、其余一律
`0.2s ease-in-out`。所有动效遵循 `prefers-reduced-motion`，系统开启「减弱动态效果」时自动关闭。

本页的动效都是**触发型**（进视口播一次）；需要「滚动条就是时间轴」的**进度驱动型**叙事
（笔记本随滚动开合、分步功能介绍），见[「滚动叙事」](/guide/scroll)。

每个演示都配了「重新播放」—— 通过重挂载（`:key` 递增）再次触发同一动效。

## 动效令牌

| 令牌 | 值 | 用途 |
| --- | --- | --- |
| `--ev-ease-spring` | `cubic-bezier(0.3, 1.3, 0.3, 1)` | 弹性入场（滑块、徽标弹入） |
| `--ev-ease-smooth` | `cubic-bezier(0.34, 0.69, 0.1, 1)` | 位移滑动（轮播、开关、卡片） |
| `--ev-ease-out` | `cubic-bezier(0.215, 0.61, 0.355, 1)` | 淡入 |
| `--ev-duration-fast / base / slow / slower` | 0.15 / 0.2 / 0.3 / 0.5s | 时长阶 |

## v-reveal 滚动入场

元素进入视口时浮现。五种方向变体 + 交错延迟，默认只触发一次（`once: false` 可反复触发）：

```vue
<div v-reveal="{ type: 'zoom', delay: 240 }">…</div>
```

## 数字滚动

[EvStatistic](/components/statistic) 的 `animated` 属性让数值进入视口时从 0 滚到目标值：
easeOutExpo 缓动（起步迅猛、收尾徐缓），自动解析前后缀（`120K+`、`99.99%`、`¥68`）：

```vue
<EvStatistic value="1,200+" label="周下载" align="center" animated :duration="1600" />
```

## 内建动效的组件

| 组件 | 动效 |
| --- | --- |
| [EvMarquee](/components/marquee) | 无限滚动横幅；文本模式 = 商场 LED 大字（实心/描边交替） |
| [EvTabs](/components/tabs) | capsule 分段滑块弹性跟随激活项 |
| [EvFeatureGrid](/components/feature-grid) | cards 默认交错入场（`reveal` / `stagger` 控制） |
| [EvHero](/components/hero) | `reveal` 开启后徽章→标题→描述→动作 90ms 错峰入场 |
| [EvNavbar](/components/navbar) | `hide-on-scroll` 下滑隐藏上滑浮现；滚动磨砂 |
| [EvCarousel](/components/carousel) | 平滑位移轮播 + 自动播放 |
| [EvCard](/components/card) / [EvArticleCard](/components/article-card) | 悬浮轻抬 + 封面缓放 |
| [EvFaq](/components/faq) | grid-rows 平滑展开 |
| [EvSwitch](/components/switch) / [EvIconGrid](/components/icon-grid) | spring 滑块 / 徽标弹入 |

## 动感文本滚动

```vue
<EvMarquee
  :items="['EVOKE UI', 'CLEAN NAVY', '轻与快', 'DELIGHTFUL MOTION']"
  separator="star-fill"
  alternate-outline
  :duration="14000"
  text-size="44px"
/>
```

## 重新触发动效的通用手法

一次性动效（reveal / count-up）重放的最简方式是**重挂载**——给容器绑定递增的 `:key`：

```vue
<script setup>
import { ref } from 'vue'
const countKey = ref(0)
</script>

<template>
  <EvButton size="small" variant="outline" icon="refresh" @click="countKey++">
    重新播放
  </EvButton>
  <EvStatistic :key="countKey" value="1,200+" animated />
</template>
```
