motion/react

Pcjmy2026-02-07React动画React

motion/react

简介

motion/react 是一个现代化的 React 动画库,提供声明式 API 来创建流畅、高性能的动画效果。

主要特性

  1. 声明式动画:通过简洁的 props 定义动画状态,无需编写复杂的动画逻辑。
  2. 高性能渲染:充分利用硬件加速和优化的渲染策略,确保动画丝滑流畅。
  3. 无缝集成:与 React 生态完美融合,原生支持 TypeScript。
  4. 丰富交互:内置拖拽、悬停、点击等多种交互手势的动画响应。

工作原理

传统 React 动画库通常依赖 React 的 diff 更新机制来实现元素属性变化,每次动画帧都需要经过 React 的渲染周期,这在复杂动画场景下容易造成性能瓶颈。

motion/react 在 React 内部实现了一套独立的动画更新系统

特性说明
绕过渲染周期直接操作 DOM 元素的视觉属性,不触发 React 重新渲染
硬件加速专注于 transformopacity 等可硬件加速的属性
流畅性能避免 React 协调过程带来的帧率损耗

💡 理解这一机制是熟练使用 motion/react 的关键——它决定了为什么某些写法性能更好,以及如何合理组织动画代码。

基础用法

1. 状态动画

motion/react 提供了 initialanimatetransition 等属性来定义元素的动画状态。

import * as motion from 'motion/react-client';

export default function EnterAnimation() {
  return (
    <motion.div
      initial={{ opacity: 0, scale: 0 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{
        duration: 0.4,
        scale: { type: 'spring', visualDuration: 0.4, bounce: 0.5 },
      }}
      style={ball}
    />
  )
}

const ball = {
  width: 100,
  height: 100,
  backgroundColor: '#dd00ee',
  borderRadius: '50%',
}

2. 交互式动画

motion/react 支持多种交互事件,如悬停、点击、拖拽等。

import * as motion from 'motion/react-client'

export default function Gestures() {
  return <motion.div whileHover={{ scale: 1.2 }} whileTap={{ scale: 0.8 }} style={box} />
}

const box = {
  width: 100,
  height: 100,
  backgroundColor: '#9911ff',
  borderRadius: 5,
}

3. 拖拽功能

motion/react 提供了强大的拖拽功能,可以轻松实现可拖拽元素。

import { motion, useMotionValue, useMotionValueEvent } from "motion/react";
import { useState } from "react";

export default function DraggableCard() {
  const x = useMotionValue(0);
  const y = useMotionValue(0);

  const [coords, setCoords] = useState({ x: 0, y: 0 });

  // 订阅 motion value 的变化
  useMotionValueEvent(x, "change", (latest) => {
    setCoords((prev) => ({ ...prev, x: latest }));
  });

  useMotionValueEvent(y, "change", (latest) => {
    setCoords((prev) => ({ ...prev, y: latest }));
  });

  return (
    <div style={{ height: "100vh", display: "flex", justifyContent: "center", alignItems: "center" }}>
      <motion.div
        drag
        style={{
          width: 100,
          height: 100,
          backgroundColor: "skyblue",
          borderRadius: 20,
          x, // 绑定 motion value
          y,
        }}
      />
      <div style={{ marginLeft: 20 }}>
        <p>X: {coords.x.toFixed(0)}</p>
        <p>Y: {coords.y.toFixed(0)}</p>
      </div>
    </div>
  );
}

4. 转换动画

motion/react 支持各种变换动画,如旋转、平移、缩放等。

import * as motion from 'motion/react-client'

export default function Rotate() {
  return <motion.div style={box} animate={{ rotate: 360 }} transition={{ duration: 1 }} />
}

const box = {
  width: 100,
  height: 100,
  backgroundColor: '#ff0088',
  borderRadius: 5,
}

5. 共享布局动画

motion/react 提供了 layoutId 属性来实现共享布局动画,这在标签切换、列表重排等场景中非常有用。

import { motion } from 'motion/react'
import { useState } from 'react'

const tabs = ['首页', '产品', '关于']

export default function TabSwitch() {
  const [activeTab, setActiveTab] = useState(0)

  return (
    <div style={{ display: 'flex', gap: 4, padding: 4, background: '#f0f0f0', borderRadius: 8 }}>
      {tabs.map((tab, index) => (
        <button
          key={tab}
          onClick={() => setActiveTab(index)}
          style={{
            position: 'relative',
            padding: '8px 16px',
            border: 'none',
            background: 'transparent',
            cursor: 'pointer',
            fontSize: 14,
          }}
        >
          {tab}
          {activeTab === index && (
            <motion.div
              layoutId="activeTab"
              style={{
                position: 'absolute',
                inset: 0,
                background: 'white',
                borderRadius: 6,
                zIndex: -1,
                boxShadow: '0 1px 3px rgba(0,0,0,0.1)',
              }}
              transition={{ type: 'spring', stiffness: 500, damping: 30 }}
            />
          )}
        </button>
      ))}
    </div>
  )
}

高级特性

1. Motion Values

Motion Values 是 motion/react 中的核心概念,它们是响应式的数值,可以在动画过程中被监听和修改。

const x = useMotionValue(0);
const y = useMotionValue(0);

// 监听值的变化
useMotionValueEvent(x, "change", (latest) => {
  console.log("X value changed:", latest);
});

2. 自定义过渡效果

motion/react 支持多种过渡类型,包括弹簧、惯性、关键帧等。

<motion.div
  animate={{ x: 100 }}
  transition={{
    type: "spring",
    stiffness: 100,
    damping: 10
  }}
/>

3. 动画序列

可以使用 key 属性和 AnimatePresence 组件来创建动画序列。

<AnimatePresence mode="wait">
  <motion.div
    key={currentStep}
    initial={{ opacity: 0, x: 100 }}
    animate={{ opacity: 1, x: 0 }}
    exit={{ opacity: 0, x: -100 }}
  >
    Step {currentStep}
  </motion.div>
</AnimatePresence>

性能优化

1. 优先使用 transform 和 opacity

motion/react 的动画系统对 transformopacity 做了特殊优化,这些属性不会触发布局重排和重绘,能够充分利用 GPU 加速。

// ✅ 推荐:使用 transform 和 opacity
<motion.div
  animate={{ x: 100, opacity: 0.5, scale: 1.2 }}
/>

// ❌ 避免:动画化会触发重排的属性
<motion.div
  animate={{ width: 200, height: 200, left: 100 }}
/>

2. 使用 layout 属性优化布局动画

当需要动画化布局属性(如宽高、位置)时,使用 layout 属性让 motion/react 自动处理布局变化,避免手动计算。

// ✅ 使用 layout 属性处理布局变化
<motion.div
  layout
  style={{ width: isExpanded ? 300 : 100 }}
  transition={{ type: "spring", stiffness: 300, damping: 30 }}
/>

3. 合理使用 will-change

对于复杂的动画,可以通过 will-change 提示浏览器提前优化:

<motion.div
  animate={{ x: 100 }}
  style={{ willChange: "transform" }}
/>

4. 避免不必要的 Motion Values 更新

使用 useTransformuseSpring 创建派生值,避免在渲染周期中直接修改 Motion Values:

import { useMotionValue, useTransform, useSpring } from "motion/react";

function SmoothAnimation() {
  const x = useMotionValue(0);
  
  // ✅ 使用 useSpring 创建平滑的派生值
  const smoothX = useSpring(x, { stiffness: 300, damping: 30 });
  
  // ✅ 使用 useTransform 映射值范围
  const opacity = useTransform(x, [0, 100], [1, 0]);
  
  return <motion.div style={{ x: smoothX, opacity }} />;
}

5. 懒加载动画组件

对于不在首屏的动画,可以使用动态导入减少初始加载开销:

import { lazy, Suspense } from "react";

const HeavyAnimation = lazy(() => import("./HeavyAnimation"));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyAnimation />
    </Suspense>
  );
}

6. 使用 reducedMotion

尊重用户的系统偏好,为不喜欢动画的用户提供降级体验:

import { useReducedMotion } from "motion/react";

function AccessibleAnimation() {
  const shouldReduceMotion = useReducedMotion();
  
  return (
    <motion.div
      animate={shouldReduceMotion ? {} : { x: 100, opacity: 0.5 }}
      transition={{ duration: shouldReduceMotion ? 0 : 0.3 }}
    />
  );
}

总结

motion/react 是一个功能强大且易于使用的 React 动画库,它提供了简洁的 API 来创建高性能的动画效果。通过合理使用其提供的各种功能,开发者可以轻松地为应用添加流畅的交互动画,提升用户体验。

无论是基础的进入/退出动画,还是复杂的拖拽和共享布局动画,motion/react 都能提供优雅的解决方案。随着 Web 应用对用户体验要求的不断提高,掌握 motion/react 将成为前端开发者的必备技能之一。

Last Updated 2026/2/7 20:46:33