前端开发 / 使用 Framer Motion 为应用添加动画效果

在 React 项目中,使用 Framer Motion 库来添加动画效果。

前端开发 / 使用 Framer Motion 为应用添加动画效果

Framer Motion 简介

什么是 Framer Motion

Framer Motion 是一个用于 React 的开源动画库。它以简洁、直观的 API 为 React 组件提供了强大的动画和交互能力。

image-20230821112506714

该库的背后是Framer,一个流行的原型设计工具,但 Framer Motion 可以作为一个独立的库用于任何 React 项目。

Framer Motion 官方网站: https://www.framer.com/motion/

Framer Motion 的优点

Framer Motion 相当年轻,初次发布是在 2019 年。

相较于其他用于实现前端动画的工具,它具有以下优点:

  1. 直观的 API: Framer Motion 的 API 非常直观和人性化,特别是对于 React 开发者来说。它使用了 React 的道具( props )系统,使得为组件添加动画和交互变得十分简单。
  2. 物理动画: Framer Motion 支持基于真实物理的动画,如弹簧。这些动画不仅看起来更自然,而且不需要复杂的配置。
  3. 自动布局动画:当组件在屏幕上的位置改变时, Framer Motion 可以自动地为它提供平滑的过渡效果,无需任何额外的配置。
  4. 良好的社区支持和文档: Framer Motion 拥有一个积极的社区,提供了丰富的资源和很好的文档支持。
  5. 性能:与其他动画库相比, Framer Motion 注重性能优化,使其在多数设备上都能流畅运行。
  6. 专为 React 设计:与一些其他通用的前端动画库相比, Framer Motion 是专门为 React 设计的,这使得它与 React 的工作方式完美结合。

Framer Motion 能实现什么效果

你可以在这里预览 Framer Motion 动画效果: https://www.framer.com/motion/examples/
image-20230821113432797

使用 Framer Motion ,你可以实现以下效果(但不仅限于此):

  • 基础动画:例如淡入、淡出、缩放、旋转、移动等。
  • 拖放交互:可以为组件添加拖动功能,并定义拖动的方向、约束等。
  • 基于物理的动画:例如弹簧效果,它可以使动画更自然和生动。
  • 布局动画:当组件的布局改变时(例如,一个列表项从一个位置移动到另一个位置), Framer Motion 可以自动地为其提供过渡效果。
  • SVG 路径动画:可以轻松地为 SVG 路径创建动画效果。
  • 复杂序列动画:使用它的动画控制和变种( variants )系统,你可以定义复杂的动画序列,而不会使代码变得混乱。
  • 共享布局转换:当两个不同的组件有相同的视觉元素时(例如,一个列表项变成了一个详情页的头部), Framer Motion 可以在这两个组件之间创建无缝的动画过渡。

安装 Framer Motion

Framer Motion 需要 React 18 或更高版本。

通过 npm 安装:

npm install framer-motion --legacy-peer-deps 

安装后,您可以通过 framer-motion 导入 Framer Motion :

import { motion } from "framer-motion"

Motion 组件( motion.div )

示例代码

<motion.div
    initial={{ opacity: 0.5, scale: 0.8 }}
    animate={{ opacity: 1, scale: 1 }}
    transition={{
      duration: 0.8,
      // delay: 0.5,
      ease: [0, 0.71, 0.2, 1.01],
    }}
    //whileInView={{ opacity: 1, scale: 1 }} // 和 animate 用法一样
    //viewport={{ once: true }}
    whileHover={{ scale: 1.05 }}
  >
  • animate:定义动画的目标或最终状态。您可以在这里设置任何您想要的属性值,例如透明度、比例、旋转等。
  • initial:定义动画的初始状态。当组件首次渲染时,它会开始于这个状态。
  • transition:定义从初始状态到动画状态的过渡效果。这里可以设置过渡的持续时间、延迟、缓动函数等

animate | 动画最终状态

<motion.div animate={{ x: 100 }} />

transition |过渡效果

官方文档: https://www.framer.com/motion/transition/

Motion 组件动画效果模板收集

Option 1.从下到上出现

<motion.div
    initial={{ translateY: "50%", opacity: 0.1 }}
        whileInView={{ translateY: "0%", opacity: 1 }}
    viewport={{ once: true }}
    transition={{
      duration: 0.8,
      // ease: [0, 0.71, 0.2, 1.01], // 轻微减速效果
      ease: [0.2, 0.88, 0.32, 1.1], // 回弹效果
    }}

    // whileHover={{ scale: 1.05 }}
  >

Option 2.放大出现

<motion.div
    initial={{ opacity: 0, scale: 0.5 }}
    whileInView={{ opacity: 1, scale: 1 }}
    viewport={{ once: true }}
    transition={{
      duration: 0.8,
      ease: [0, 0.71, 0.2, 1.01],
    }}
    // whileHover={{ scale: 1.05 }}
  >

Option 3. 模糊出现

<motion.div
  initial={{ opacity: 1, scale: 0.8, filter: "blur(10px)" }}
  whileInView={{ opacity: 1, scale: 1, filter: "blur(0px)" }}
  // viewport={{ once: true }}
  transition={{
    duration: 0.5,
    ease: [0, 0.5, 0.8, 1],
  }}
  // whileHover={{ scale: 1.05 }}
  whileHover={{ scale: 1.1 }}
  whileTap={{ scale: 0.9 }}
>

Option 4.从下到上+模糊混合

 <motion.div
    initial={{ translateY: "50%", opacity: 0.5, filter: "blur(20px)" }}
    whileInView={{
      translateY: "0%",
      opacity: 1,
      scale: 1,
      filter: "blur(0px)",
    }}
    viewport={{ once: true }}
    transition={{
      duration: 0.5,
      ease: [0.2, 0.88, 0.32, 1.1], // 回弹效果
    }}
    whileHover={{ scale: 1.1 }}
    whileTap={{ scale: 0.9 }}
  >

设置页面首次加载时,不应用效果

检测元素何时进入视窗( Scroll-triggered )

Famer Motion 提供了 3 种方法来处理元素进入窗口时的动作:

方法特点劣势
whileInView 👍– 动画属性( animation prop )
– 使用最简单的 API ,最常用
– 无法实现更高自定义要求
useInView– React Hook
– 可以和其他 React 状态结合使用
– 使用比 whileInView 复杂
inView– React Hook
– 基于浏览器的本机 API 构建,可实现最佳性能/最小文件
– 使用最复杂

whileInView 方法

官方文档地址: https://www.framer.com/motion/scroll-animations/#scroll-triggered-animations

使用示例:

<motion.div
  initial={{ opacity: 0 }}
  whileInView={{ opacity: 1 }}
  viewport={{ once: true }}
  // whileHover={{ scale: 1.05 }}
>

viewport | 常结合使用

官方文档地址: https://www.framer.com/motion/scroll-animations/##viewport-options
  • once:true 只触发一次效果

onViewportEnte | 进入时的回调

TODO

onViewportLeave | 离开时的回调

TODO

常见问题

Error: Replace exitBeforeEnter with mode=’wait’

Framer Motion 中的 exitBeforeEnter 属性可确保,前一个组件在加载下一个组件及其各自的动画之前被卸载,这样组件之间的更改将是无缝的。

属性 exitBeforeEnter 在新版中已被弃用,替换为 mode='wait' 即可。

更多说明可以参考官方文档: https://www.framer.com/motion/animate-presence/###mode

Framer Motion 基础知识

AnimatePresence 和 motion 组件的作用

示例代码:

return (
    <AnimatePresence mode="wait">
      {open && (
        <motion.div
          initial="hidden"
          animate="visible"
          exit="exit"
          variants={modalVariants}
          className="fixed inset-0 z-10 overflow-y-auto"
          role="dialog"
          aria-modal="true"
        >
          <div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
            <div
              className="fixed inset-0 transition-opacity"
              onClick={closeModal}
            >
              <div className="absolute inset-0 bg-gray-900 opacity-75" />
            </div>
            <span className="hidden sm:inline-block sm:h-screen sm:align-middle" />
            <motion.div className="inline-block transform overflow-hidden overflow-y-auto rounded-lg bg-white text-left align-bottom shadow-xl transition-all max-h-[90vh] sm:w-full sm:max-w-md sm:align-middle 2xl:max-w-lg">
              {children}
              <CloseButton onClick={closeModal} />
            </motion.div>
          </div>
        </motion.div>
      )}
    </AnimatePresence>
  );
};

motion 和 AnimatePresence 在 framer-motion 的实践中经常一起使用。

例如,当你有一个条件渲染的模态框或路由切换的页面时,你可能想为这些元素添加平滑的进入和离开动画。

在这种情况下:

  • motion 组件提供了动画的具体细节。
  • AnimatePresence 确保了在元素被移除之前可以执行适当的退出动画。

所以,尽管你可以单独使用它们,但它们经常一起使用来实现更复杂的动画效果。

motion

motion 是 framer-motion 的核心组件之一,提供了一种简单的方法来为 React 组件添加动画。例如,你可以将标准的 div 替换为 motion.div,然后为其提供一些动画属性和方法,从而使该 div 具有动画效果。

使用场景:使用 motion 当你想要给一个元素添加动画。

AnimatePresence

AnimatePresence 是一个包裹器组件,用于侦测其子组件何时进入或离开 DOM 。当它检测到子组件被移除时,它允许子组件(通常是 motion 组件)执行定义的退出动画。

使用场景:使用 AnimatePresence 当你想要处理元素的进入和退出动画,尤其是在该元素可能会突然出现或消失的情况下。