framer-motion、lottie-react-native、react-native-animatable、react-native-reanimated、react-spring 和 react-transition-group 都是用于在 React 或 React Native 应用中实现动画效果的流行库,但它们的设计目标、性能特征和适用场景差异显著。framer-motion 和 react-spring 主要面向 Web 端,提供声明式、物理驱动的动画能力;react-transition-group 专注于基于状态变化的进入/离开过渡;而 react-native-reanimated、lottie-react-native 和 react-native-animatable 则专为 React Native 设计,分别针对高性能原生动画、Lottie JSON 动画集成和简单内置动画封装。这些库在渲染线程、API 风格、性能开销和跨平台支持方面存在关键区别,开发者需根据项目平台、动画复杂度和性能要求进行权衡。
在现代前端开发中,动画不仅是视觉点缀,更是提升用户体验的关键手段。然而,面对 framer-motion、lottie-react-native、react-native-animatable、react-native-reanimated、react-spring 和 react-transition-group 这些主流动画库,开发者常陷入“选哪个”的困境。本文从真实工程视角出发,深入剖析它们的核心机制、适用边界与性能特征,助你做出精准技术决策。
首先明确一点:这些库并非完全可互换。它们分为 Web 专用、React Native 专用 和 跨平台 三类。
framer-motion、react-spring(默认配置)、react-transition-grouplottie-react-native、react-native-animatable、react-native-reanimatedreact-spring(通过 @react-spring/native 支持 RN)⚠️ 注意:
react-native-animatable自 2019 年起已无实质性更新,官方仓库标记为“不再积极维护”,强烈不建议在新项目中使用。
react-transition-group如果你只需要在组件挂载/卸载时添加简单过渡(如淡入淡出),react-transition-group 是最轻量的选择。它不处理复杂动画逻辑,而是帮你管理 CSS 类名切换。
// react-transition-group
import { CSSTransition } from 'react-transition-group';
function Fade({ in: inProp }) {
return (
<CSSTransition in={inProp} timeout={300} classNames="fade">
<div>Hello</div>
</CSSTransition>
);
}
/* 对应 CSS */
.fade-enter { opacity: 0; }
.fade-enter-active { opacity: 1; transition: opacity 300ms; }
framer-motionframer-motion 以极简 API 实现复杂交互动画,尤其擅长布局动画和手势集成。
// framer-motion
import { motion } from 'framer-motion';
<motion.div
animate={{ x: 100, rotate: 360 }}
transition={{ type: 'spring', stiffness: 300 }}
/>
// 布局动画示例
<motion.div layout>
{isOpen && <motion.div layoutId="panel">Content</motion.div>}
</motion.div>
react-springreact-spring 基于弹簧物理模型,适合需要自然弹性效果的场景(如拖拽回弹、数据可视化)。
// react-spring
import { useSpring, animated } from 'react-spring';
function SpringBox() {
const props = useSpring({ x: 100, rotate: 360 });
return <animated.div style={props} />;
}
// 手势集成
const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }));
const bind = useDrag(({ offset: [x, y] }) => api.start({ x, y }));
return <animated.div {...bind()} style={{ x, y }} />;
react-native-reanimatedreact-native-reanimated 的核心优势在于将动画逻辑移至 UI 线程执行,彻底规避 JavaScript 线程卡顿。其 API 分为 v1(回调式)和 v2(工作lets),v2 更推荐。
// react-native-reanimated (v2)
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated';
function ReanimatedBox() {
const offset = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => {
return { transform: [{ translateX: offset.value }] };
});
const onPress = () => {
offset.value = withSpring(100);
};
return <Animated.View style={animated_style} onTouchEnd={onPress} />;
}
lottie-react-native该库仅用于渲染设计师导出的 Lottie JSON 文件,不提供程序化动画能力。
// lottie-react-native
import LottieView from 'lottie-react-native';
<LottieView
source={require('./animation.json')}
autoPlay
loop
/>
react-native-animatable所有动画在 JS 线程运行,性能较差,仅作历史参考。
// react-native-animatable (不推荐)
import Animatable from 'react-native-animatable';
<Animatable.View animation="fadeIn" duration={500} />
| 库 | 渲染线程 | 性能瓶颈 | 适用场景 |
|---|---|---|---|
framer-motion | Web 主线程 | 复杂布局重排 | Web UI 交互动画 |
react-spring | Web 主线程 | 高频更新计算 | 物理模拟、数据可视化 |
react-transition-group | Web 主线程 | 极低(仅类名切换) | 简单进入/离开过渡 |
react-native-reanimated | UI 线程 | 几乎无 | RN 高性能交互动画 |
lottie-react-native | 原生渲染线程 | Lottie 文件复杂度 | 播放预设矢量动画 |
react-native-animatable | JS 线程 | 明显卡顿 | 避免使用 |
framer-motionAnimatePresence 和 layoutId 完美解决此问题// framer-motion 路由动画
import { AnimatePresence, motion } from 'framer-motion';
<AnimatePresence mode="wait">
<motion.div
key={location.pathname}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
{children}
</motion.div>
</AnimatePresence>
react-native-reanimated + react-native-gesture-handler// reanimated 拖拽示例(简化)
const dragX = useSharedValue(0);
const gestureHandler = useAnimatedGestureHandler({
onActive: (event) => { dragX.value = event.translationX; },
onEnd: () => { dragX.value = withSpring(0); }
});
const style = useAnimatedStyle(() => ({ transform: [{ translateX: dragX.value }] }));
return <PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={style} />
</PanGestureHandler>;
react-spring@react-spring/web 和 @react-spring/native 提供统一 API// react-spring 跨平台数字动画
import { useSpring, animated } from '@react-spring/web'; // Web
// import { useSpring, animated } from '@react-spring/native'; // RN
function NumberDisplay({ value }) {
const { number } = useSpring({ number: value });
return <animated.text>{number.to(n => n.toFixed(0))}</animated.text>;
}
lottie-react-native(RN)或 lottie-web(Web)Web 项目:
react-transition-groupframer-motionreact-springReact Native 项目:
react-native-reanimatedlottie-react-nativereact-native-animatable通用原则:
最终,没有“最好”的库,只有“最合适”的工具。理解每个库的底层机制和设计哲学,才能在正确的时间选用正确的武器。
选择 framer-motion 如果你正在构建 Web 应用,需要高度声明式、可组合的动画 API,并希望利用其内置的布局动画(layout animations)、手势交互(drag, hover)和共享元素过渡。它适合中等复杂度的 UI 动画,如卡片展开、路由切换、悬停反馈等,但不适用于需要精细控制或极致性能的复杂物理模拟。
选择 react-transition-group 如果你只需要处理组件的进入(enter)、退出(exit)和出场(appear)过渡,尤其是配合 CSS 类名或内联样式实现简单的淡入淡出、滑动效果。它轻量、专注,适合路由切换、模态框显示/隐藏等场景,但不提供高级动画能力(如手势、物理模拟或原生线程优化);若需更强大功能,应考虑 framer-motion 或 react-spring。
选择 react-native-reanimated 如果你在 React Native 中需要高性能、流畅的动画(如手势驱动交互动画、自定义转场),尤其是当动画必须在 UI 线程运行以避免 JS 线程阻塞时。它学习曲线较陡,但提供了底层原生动画能力,适合构建复杂交互(如可拖拽面板、自定义导航转场)或对 60fps 有严格要求的场景。
选择 react-spring 如果你需要基于物理弹簧模型的自然动画效果(如弹性、阻尼),并希望在 Web 或 React Native(通过 @react-spring/native)之间共享动画逻辑。它比 CSS 过渡更灵活,适合数据可视化、复杂状态插值或需要精确控制动画曲线的场景,但需注意其声明式 API 可能带来额外的认知负担。
选择 lottie-react-native 如果你需要在 React Native 应用中嵌入由 After Effects 导出的 Lottie JSON 动画文件(例如加载指示器、品牌动效或复杂矢量动画)。它不适用于程序化生成的动画逻辑,而是作为设计师交付资产的播放器,适合复用预制作动画内容而非编写代码驱动的动态行为。
选择 react-native-animatable 仅当你需要快速实现简单的内置动画(如 fadeIn、bounceIn)且项目对性能要求不高。该库已多年未积极维护,所有动画均在 JavaScript 线程运行,可能导致卡顿,不推荐用于新项目;应优先评估 react-native-reanimated 或其他现代替代方案。
npm install motion
Motion is available for React, JavaScript and Vue.
import { motion } from "motion/react"
function Component() {
return <motion.div animate={{ x: 100 }} />
}
Get started with Motion for React.
import { animate } from "motion"
animate("#box", { x: 100 })
Get started with JavaScript.
<script>
import { motion } from "motion-v"
</script>
<template> <motion.div :animate={{ x: 100 }} /> </template>
Get started with Motion for Vue.
Browse 100+ free and 180+ premium Motion Examples, with copy-paste code that'll level-up your animations whether you're a beginner or an expert.
A one-time payment, lifetime-updates membership:
Motion is sustainable thanks to the kind support of its sponsors.
Motion powers the animations for all websites built with Framer, the web builder for creative pros. The Motion website itself is built on Framer, for its delightful canvas-based editing and powerful CMS features.
Motion drives the animations on the Cursor homepage, and is working with Cursor to bring powerful AI workflows to the Motion examples and docs.