图像与设计
为 React/Web 应用添加页面过渡、滚动动画…
在 React/Next.js 项目中需要实现 UI 动画、过渡、滚动效果或加载/反馈动画时,可参考这些 Framer Motion 与 CSS 模式。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
为 React/Web 应用添加页面过渡特定
解决思路
- 安装依赖:运行 `npm install framer-motion`。
- 基础动画:从 `framer-motion` 导入 `motion`,用 `motion.div` 设置 `initial={{ opacity: 0 }}`、`animate={{ opacity: 1 }}`、`transition={{ duration: 0.5 }}`。
- Pattern 1 Fade In on Mount:用 `motion.div`,设置 `initial={{ opacity: 0, y: 20 }}`、`animate={{ opacity: 1, y: 0 }}`、`transition={{ duration: 0.4, ease: 'easeOut' }}`,可加 className。
- Pattern 2 Staggered List Animation:定义 `container` variants:`hidden: { opacity: 0 }`、`show: { opacity: 1, transition: { staggerChildren: 0.1 } }`;定义 `item` variants:`hidden: { opacity: 0, y: 20 }`、`show: { opacity: 1, y: 0 }`;`motion.ul` 使用 `variants={container}`、`initial='hidden'`、`animate='show'`;列表项用 `motion.li` 并绑定 `variants={item}`。
- Pattern 3 Button Hover Animation:用 `motion.button`,设置 `whileHover={{ scale: 1.05 }}`、`whileTap={{ scale: 0.95 }}`、`transition={{ type: 'spring', stiffness: 400, damping: 17 }}`。
- Pattern 4 Modal / Dialog Animation:用 `AnimatePresence` 包裹条件渲染;背景 `motion.div` 设置 `initial={{ opacity: 0 }}`、`animate={{ opacity: 1 }}`、`exit={{ opacity: 0 }}`、`onClick={onClose}` 和 fixed 全屏样式;弹窗 `motion.div` 设置 `initial={{ opacity: 0, scale: 0.9, y: 20 }}`、`animate={{ opacity: 1, scale: 1, y: 0 }}`、`exit={{ opacity: 0, scale: 0.9, y: 20 }}`、`transition={{ type: 'spring', damping: 25, stiffness: 300 }}`。
- Pattern 5 Page Transition:在 Next.js 客户端组件中 `'use client'`,导入 `motion` 和 `usePathname`;用 `const pathname = usePathname()`;`motion.div` 绑定 `key={pathname}`,设置 `initial={{ opacity: 0, x: 20 }}`、`animate={{ opacity: 1, x: 0 }}`、`exit={{ opacity: 0, x: -20 }}`、`transition={{ duration: 0.3 }}`;在 layout 中包裹 children。
- Scroll-Triggered Animation:用 `useRef` 创建 ref,`useScroll({ target: ref, offset: ['start end', 'end start'] })` 获取 `scrollYProgress`;用 `useTransform` 把 `[0, 0.3, 0.7, 1]` 映射为 opacity `[0, 1, 1, 0]` 和 y `[100, 0, 0, -100]`;在 `motion.div` 上设置 `ref` 和 `style={{ opacity, y }}`。
- Parallax Effect:用 `useScroll()` 获取 `scrollY`,用 `useTransform(scrollY, [0, 500], [0, 150])` 得到 y;容器用 `relative h-screen overflow-hidden`,背景 `motion.div` 用 `style={{ y }}` 和 `absolute inset-0`,图片铺满,前景内容用 `relative z-10`。
- Scroll Progress Indicator:用 `useScroll()` 获取 `scrollYProgress`,`motion.div` 设置 `style={{ scaleX: scrollYProgress }}`,样式 `fixed top-0 left-0 right-0 h-1 bg-blue-600 origin-left z-50`。
- Spinner:用 `motion.div` 设置 `animate={{ rotate: 360 }}`、`transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}`,配合边框圆环样式。
- Skeleton Loader:用 `motion.div` 设置 `animate={{ opacity: [0.5, 1, 0.5] }}`、`transition={{ duration: 1.5, repeat: Infinity, ease: 'easeInOut' }}`,配合 `bg-gray-200 rounded h-4 w-full`。
- Pulsing Dots:定义 `dotVariants`:`start: { scale: 0.8, opacity: 0.5 }`、`end: { scale: 1.2, opacity: 1 }`;映射 3 个 `motion.div`,设置 `variants`、`animate='end'`、`initial='start'`、`transition={{ duration: 0.6, repeat: Infinity, repeatType: 'reverse', delay: i * 0.2 }}`。
- CSS Keyframe Animations:编写 `@keyframes fadeIn`:`from { opacity: 0; transform: translateY(20px); }`、`to { opacity: 1; transform: translateY(0); }`,`.fade-in { animation: fadeIn 0.5s ease-out; }`。
- CSS Keyframe Animations:编写 `@keyframes slideInRight`:`from { transform: translateX(100%); }`、`to { transform: translateX(0); }`,`.slide-in-right { animation: slideInRight 0.3s ease-out; }`。
- CSS Keyframe Animations:编写 `@keyframes bounce`:`0%,100% { transform: translateY(0); }`、`50% { transform: translateY(-10px); }`,`.bounce { animation: bounce 0.5s ease-in-out infinite; }`。
- Tailwind Animations:在 `tailwind.config.js` 的 `theme.extend.keyframes` 中定义 `'fade-in'` 和 `'slide-in'`,在 `theme.extend.animation` 中定义 `'fade-in': 'fade-in 0.5s ease-out'`、`'slide-in': 'slide-in 0.3s ease-out'`;使用时加 `animate-fade-in`、`animate-slide-in` class。
- Success Checkmark Animation:用 `motion.svg` 设置 `initial={{ scale: 0 }}`、`animate={{ scale: 1 }}`、`transition={{ type: 'spring', stiffness: 300, damping: 20 }}`;`motion.circle` 设置 `initial={{ pathLength: 0 }}`、`animate={{ pathLength: 1 }}`、`transition={{ duration: 0.5 }}`;`motion.path` 绘制勾,设置 `pathLength: 0 -> 1`、`transition={{ duration: 0.3, delay: 0.3 }}`。
- Notification Badge:当 `count > 0` 时渲染 `motion.div`,设置 `initial={{ scale: 0 }}`、`animate={{ scale: 1 }}`、`transition={{ type: 'spring', stiffness: 500, damping: 15 }}`,用绝对定位放在按钮右上角。
- Performance:优先动画 `transform` 和 `opacity`(GPU 加速),如 `x`、`opacity`;不要动画 `width`、`height` 等会触发布局的属性。
- Duration:避免 `< 100ms`(太突兀)和 `> 500ms`(太拖沓);大多数 UI 动画使用 `200-400ms`,例如 `transition={{ duration: 0.3 }}`。
- Easing:自然运动用 `easeOut`(快速开始、缓慢结束);弹性效果用 `spring`,例如 `type: 'spring', stiffness: 400`。
- Reduce Motion:导入 `useReducedMotion`;用 `const shouldReduceMotion = useReducedMotion()`;当为 true 时把 `y` 设为 0、`duration` 设为 0,否则用 `y: 20`、`duration: 0.4`。
- Drag and Drop:用 `motion.div` 开启 `drag`,设置 `dragConstraints={{ left: 0, right: 300, top: 0, bottom: 300 }}`、`dragElastic={0.1}`;在 `onDragEnd` 中用 `info.point` 更新位置;加 `cursor-grab active:cursor-grabbing`。
- Animated Number Counter:用 `useSpring(0, { stiffness: 100, damping: 30 })`,用 `useTransform(spring, current => Math.round(current).toLocaleString())` 格式化显示;在 `useEffect` 中 `spring.set(value)`;用 `motion.span` 渲染 display;用法 `<AnimatedNumber value={1250} />`。
适用边界 · 注意事项
- 不适用于非 React/非 Web 项目中使用 Framer Motion 示例;若只有 CSS,则只能参考 CSS 动画部分。
- 不适用于不能引入 npm 依赖 `framer-motion` 或要求零依赖的项目。
- 不适用于需要动画 width/height/top/left 等布局属性且无法改用 transform/opacity 的场景。