关于 react-spring-physics
react-spring-physics 是面向 React 开发者的物理动画技能,结合 React Spring 与 Popmotion,指导构建自然、可中断并能响应交互的界面动画。
主要功能
- 01基于弹簧物理的动画
- 02手势驱动与动量效果
- 03中断动画并保留速度
- 04序列、列表与滚动动画
- 05React Three Fiber 3D 动画
适用场景
- 01构建拖动或滑动交互
- 02制作列表进入与离场效果
- 03创建滚动触发的内容显现
- 04为 Three.js 场景添加动画
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ freshtechbro/ claudedesignskills --skill react-spring-physics安装后在 Claude Code 中输入/react-spring-physics确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/README.mdreferences/physics_guide.mdpopmotion_api.mdreact_spring_api.mdscripts/physics_calculator.pyspring_generator.py详细介绍
React Spring 物理动画
面向 React 应用的物理动画,结合 React Spring 的声明式弹簧动画与 Popmotion 的底层物理工具。
概览
React Spring 提供自然且可中断的弹簧物理动画。与基于时长的动画不同,弹簧会根据物理属性(质量、张力、摩擦力)计算运动,从而产生自然、逼真的效果。Popmotion 则通过可组合的动画函数补充关键帧、衰减和惯性动画。
适用场景:
- 自然的物理效果 UI 动画
- 手势驱动的界面(拖动、滑动、滚动)
- 可响应运动过程中用户输入的可中断动画
- 状态变化时保持速度的平滑过渡
- 惯性滚动和惯性效果
核心库:
@react-spring/web- 用于弹簧动画的 React Hooks@react-spring/three- Three.js 集成popmotion- 底层动画工具(可选,适用于高级场景)
核心概念
弹簧物理
弹簧通过物理模拟将值从当前状态动画到目标状态:
import { useSpring, animated } from '@react-spring/web'
function SpringExample() {
const springs = useSpring({
from: { opacity: 0, y: -40 },
to: { opacity: 1, y: 0 },
config: {
mass: 1, // Weight of object
tension: 170, // Spring strength
friction: 26 // Opposing force
}
})
return <animated.div style={springs}>Hello</animated.div>
}
useSpring Hook 模式
适用于不同场景的两种初始化模式:
// Object config (simpler, auto-updates on prop changes)
const springs = useSpring({
from: { x: 0 },
to: { x: 100 }
})
// Function config (more control, returns API for imperative updates)
const [springs, api] = useSpring(() => ({
from: { x: 0 }
}), [])
// Trigger animation via API
const handleClick = () => {
api.start({
from: { x: 0 },
to: { x: 100 }
})
}
弹簧配置预设
React Spring 提供内置配置预设:
import { config } from '@react-spring/web'
// Available presets
config.default // { tension: 170, friction: 26 }
config.gentle // { tension: 120, friction: 14 }
config.wobbly // { tension: 180, friction: 12 }
config.stiff // { tension: 210, friction: 20 }
config.slow // { tension: 280, friction: 60 }
config.molasses // { tension: 280, friction: 120 }
// Usage
const springs = useSpring({
from: { x: 0 },
to: { x: 100 },
config: config.wobbly
})
常见模式
1. 点击触发的弹簧动画
import { useSpring, animated } from '@react-spring/web'
function ClickAnimated() {
const [springs, api] = useSpring(() => ({
from: { scale: 1 }
}), [])
const handleClick = () => {
api.start({
from: { scale: 1 },
to: { scale: 1.2 },
config: { tension: 300, friction: 10 }
})
}
return (
<animated.button
onClick={handleClick}
style={{
transform: springs.scale.to(s => `scale(${s})`)
}}
>
Click Me
</animated.button>
)
}
2. 多元素轨迹动画
import { useTrail, animated } from '@react-spring/web'
function Trail({ items }) {
const trails = useTrail(items.length, {
from: { opacity: 0, x: -20 },
to: { opacity: 1, x: 0 },
config: config.gentle
})
return (
<div>
{trails.map((style, i) => (
<animated.div key={i} style={style}>
{items[i]}
</animated.div>
))}
</div>
)
}
3. 列表过渡(进入/退出)
import { useTransition, animated } from '@react-spring/web'
function List({ items }) {
const transitions = useTransition(items, {
from: { opacity: 0, height: 0 },
enter: { opacity: 1, height: 80 },
leave: { opacity: 0, height: 0 },
config: config.stiff,
keys: item => item.id
})
return transitions((style, item) => (
<animated.div style={style}>
{item.text}
</animated.div>
))
}
4. 基于滚动的弹簧动画
import { useScroll, animated } from '@react-spring/web'
function ScrollReveal() {
const { scrollYProgress } = useScroll()
return (
<animated.div
style={{
opacity: scrollYProgress.to([0, 0.5], [0, 1]),
scale: scrollYProgress.to([0, 0.5], [0.8, 1])
}}
>
Scroll to reveal
</animated.div>
)
}
5. 视口交叉动画
import { useInView, animated } from '@react-spring/web'
function FadeInOnView() {
const [ref, springs] = useInView(
() => ({
from: { opacity: 0, y: 100 },
to: { opacity: 1, y: 0 }
}),
{ rootMargin: '-40% 0%' }
)
return <animated.div ref={ref} style={springs}>Content</animated.div>
}
6. 链式异步动画
import { useSpring, animated } from '@react-spring/web'
function ChainedAnimation() {
const springs = useSpring({
from: { x: 0, background: '#ff6d6d' },
to: [
{ x: 80, background: '#fff59a' },
{ x: 0, background: '#88DFAB' },
{ x: 80, background: '#569AFF' }
],
config: { tension: 200, friction: 20 },
loop: true
})
return <animated.div style={springs} />
}
7. 保留速度的弹簧动画
import { useSpring, animated } from '@react-spring/web'
function VelocityPreservation() {
const [springs, api] = useSpring(() => ({
x: 0,
config: { tension: 300, friction: 30 }
}), [])
const handleDragEnd = () => {
api.start({
x: 0,
velocity: springs.x.getVelocity(), // Preserve momentum
config: { tension: 200, friction: 20 }
})
}
return <animated.div style={springs} onMouseUp={handleDragEnd} />
}
集成模式
与 React Three Fiber 配合(3D)
import { useSpring, animated } from '@react-spring/three'
import { Canvas } from '@react-three/fiber'
const AnimatedBox = animated(MeshDistortMaterial)
function ThreeScene() {
const [clicked, setClicked] = useState(false)
const springs = useSpring({
scale: clicked ? 1.5 : 1,
color: clicked ? '#569AFF' : '#ff6d6d',
config: { tension: 200, friction: 20 }
})
return (
<Canvas>
<mesh onClick={() => setClicked(!clicked)} scale={springs.scale}>
<sphereGeometry args={[1, 64, 32]} />
<AnimatedBox color={springs.color} />
</mesh>
</Canvas>
)
}
与 Popmotion 配合(底层物理)
import { spring, inertia } from 'popmotion'
import { useState } from 'react'
function PopmotionIntegration() {
const [x, setX] = useState(0)
const handleDragEnd = (velocity) => {
inertia({
from: x,
velocity: velocity,
power: 0.3,
timeConstant: 400,
modifyTarget: v => Math.round(v / 100) * 100 // Snap to grid
}).start(setX)
}
return <div style={{ transform: `translateX(${x}px)` }} />
}
与表单和验证配合
import { useSpring, animated } from '@react-spring/web'
function ValidatedInput() {
const [error, setError] = useState(false)
const shakeAnimation = useSpring({
x: error ? [0, -10, 10, -10, 10, 0] : 0,
config: { tension: 300, friction: 10 },
onRest: () => setError(false)
})
return <animated.input style={shakeAnimation} />
}
性能优化
按需渲染
// Only re-render when animation is active
const [springs, api] = useSpring(() => ({
from: { x: 0 },
config: { precision: 0.01 } // Higher value = less updates
}), [])
批量处理多个弹簧
// Use useSprings for multiple similar animations
const springs = useSprings(
items.length,
items.map(item => ({
from: { opacity: 0 },
to: { opacity: 1 }
}))
)
跳过动画(测试/无障碍)
import { Globals } from '@react-spring/web'
// Skip all animations (prefers-reduced-motion)
useEffect(() => {
Globals.assign({ skipAnimation: true })
return () => Globals.assign({ skipAnimation: false })
}, [])
常见问题
1. 忘记依赖数组
// ❌ Wrong: No dependencies, creates new spring every render
const springs = useSpring(() => ({ x: 0 }))
// ✅ Correct: Empty array prevents recreation
const [springs, api] = useSpring(() => ({ x: 0 }), [])
2. 修改弹簧值
// ❌ Wrong: Direct mutation
springs.x.set(100)
// ✅ Correct: Use API to animate
api.start({ x: 100 })
3. 忽略配置精度
// ❌ Default precision too fine (0.0001), causing unnecessary renders
const springs = useSpring({ x: 0 })
// ✅ Set appropriate precision for your use case
const springs = useSpring({
x: 0,
config: { precision: 0.01 } // Stop updating when within 0.01 of target
})
4. 未处理速度
// ❌ Abrupt stop when interrupting animation
api.start({ x: 0 })
// ✅ Preserve momentum
api.start({
x: 0,
velocity: springs.x.getVelocity()
})
5. 混用配置模式
// ❌ Wrong: Using both object and function config
const springs = useSpring({
from: { x: 0 }
})
api.start({ x: 100 }) // api is undefined
// ✅ Correct: Use function config for imperative control
const [springs, api] = useSpring(() => ({
from: { x: 0 }
}), [])
6. 为非数值类型添加动画
// ❌ Wrong: Spring can't interpolate complex strings directly
const springs = useSpring({ transform: 'translateX(100px) rotate(45deg)' })
// ✅ Correct: Animate individual values
const springs = useSpring({ x: 100, rotation: 45 })
// Then combine: transform: `translateX(${x}px) rotate(${rotation}deg)`
资源
脚本
spring_generator.py- 生成 React Spring 样板代码physics_calculator.py- 计算最佳弹簧物理参数
参考资料
react_spring_api.md- React Spring Hooks 和 API 完整参考popmotion_api.md- Popmotion 函数和响应式流physics_guide.md- 弹簧物理深入介绍及调优指南
资源文件
starter_spring/- 包含 React Spring 示例的 React + Vite 模板examples/- 实际应用模式(手势、滚动、3D 集成)
相关技能
- motion-framer - 使用变体的另一种声明式动画方案
- gsap-scrolltrigger - 用于复杂序列的基于时间线的动画
- react-three-fiber - 3D 场景管理(动画使用 @react-spring/three)
- animated-component-libraries - 使用 Motion 构建的预制动画组件
物理动画与时间线动画:使用 React Spring 实现能响应用户输入的自然物理动画。使用 GSAP 实现精确的时间线编排和复杂的多步骤序列。
评论
支持 Markdown