
关于
React / Next.js 高级动效模式——拖放、手势、文字动画、SVG 路径绘制、自定义 Hooks、命令式序列(useAnimate)、加载器和完整 API 决策树。需要 motion-foundations。
name: motion-advanced description: React / Next.js 高级动效模式——拖放、手势、文本动画、SVG 路径绘制、自定义 hooks、命令式序列(useAnimate)、加载器,以及完整的 API 决策树。需要先设置 motion-foundations。 version: 1.0 tags: [motion, animation, advanced, gestures, svg] category: frontend author: jeff
Motion 高级动效
复杂的、交互式的、基于物理的动画模式。
需要先设置 motion-foundations。
当 motion-patterns 不够用时使用这些。
何时激活
- 构建拖拽关闭面板、滑动手势或可重排列表时
- 逐词、逐字符动画文本或作为实时计数器时
- 绘制 SVG 路径、变形图标或动画圆形进度时
- 编写自定义动画 hook(
useScrollReveal、磁性按钮、光标跟随器)时 - 使用
useAnimate命令式编排多步动画时 - 构建加载动画、骨架屏、脉冲指示器或按钮加载状态时
输出
此技能产出:
- 拖拽交互:可拖拽卡片、拖拽关闭面板、
Reorder.Group列表 - 手势 hooks:滑动检测、长按、捏合轮廓
- 文本动画组件:逐词显示、逐字符打字机、数字计数器
- SVG 动画:路径绘制、图标变形、描边进度环
- 自定义 hooks:
useScrollReveal、useHoverScale、useNavigationDirection、useInViewOnce - 通过
useAnimate的命令式序列,支持中断安全的async/await - 加载器组件:旋转器、骨架屏、脉冲点、进度条、按钮加载状态
原则
- 基于物理的运动(
useSpring、springs.*)对于直接操作总是比基于时长的更自然。 useMotionValue+useTransform计算派生值而不触发重新渲染。useAnimate序列是命令式的且中断安全的——在动画进行中调用animate()会自动取消前一个动画。- Motion 值(
useMotionValue、useSpring)是 SSR 安全的,不会导致水合错误。
规则
- 拖拽交互必须在触摸设备上测试,不仅仅是鼠标。
drag属性在两者上都有效,但手感和阈值不同。 - 无限动画必须在
document.visibilityState === "hidden"时暂停。 后台标签页不得消耗 GPU/CPU。 - 滑动阈值必须明确。 不要仅从速度推断意图;结合
offset+velocity检查。 useAnimate的 scope ref 必须附加到已挂载的 DOM 元素。 在挂载前调用animate()会静默失败。- Motion 值不得在渲染时重新创建。 组件体内的
useMotionValue(0)是正确的;渲染中的new MotionValue(0)不是。 - 所有 token 值从
motion-foundations导入。 不使用内联数字。 - 自定义 hooks 必须处理清理。 每个
window.addEventListener需要在useEffect返回中有匹配的removeEventListener。 - SVG 变形需要相等的路径命令数量。 具有不同命令结构的路径会跳变而非插值。
决策指导
选择正确的高级 API
| 场景 | API |
| ------------------------------ | -------------------------------- |
| 释放时带物理效果的拖拽 | drag + dragTransition: springs.release |
| 有序拖拽重排列表 | Reorder.Group + Reorder.Item |
| 拖拽偏移量达到时关闭 | drag="y" + onDragEnd 偏移检查 |
| 左右滑动 | drag="x" + onDragEnd 偏移检查 |
| 长按 | useLongPress hook |
| 随时间平滑的值 | useSpring |
| 从另一个值派生的值 | useTransform |
| 多步序列 | useAnimate 配合 async/await |
| 一次性命令式动画 | motion 的 animate() |
| 文本逐词进入 | 在 inline-block span 上交错 |
| SVG 绘制 | pathLength 0 → 1 |
| SVG 变形 | d 属性补间(相等命令) |
| 圆形进度 | strokeDashoffset 补间 |
何时使用 useSpring vs spring transition
| | useSpring | transition: springs.* |
| -------------- | ---------------------------------------- | ----------------------- |
| 用途 | 光标跟随器、指针跟踪值 | 离散状态变化 |
| 更新 | 连续的,每帧 | 由状态变化触发 |
| 中断 | 平滑——物理从速度接续 | 从当前值重新开始 |
核心概念
useMotionValue + useTransform
无需重新渲染的响应式计算:
const x = useMotionValue(0)
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0])
// opacity 在 x 变化时每帧更新——无 setState,无重新渲染
useAnimate
返回 [scope, animate]。scope ref 必须附加到 DOM 元素。
animate() 调用是中断安全的——在进行中调用会取消前一次运行。
const [scope, animate] = useAnimate()
async function play() {
await animate(".step-1", { opacity: 1 }, { duration: 0.3 })
await animate(".step-2", { x: 0 }, { duration: 0.4 })
}
