在React中实现好看的动画Framer Motion(案例:跨DOM元素平滑过渡)

前言

介绍

Framer Motion 是一个适用于 React 网页开发的动画库,它可以让开发者轻松地在他们的项目中添加复杂和高性能的动画效果。该库提供了一整套针对 React 组件的动画、过渡和手势处理功能,使得通过声明式的 API 来创建动画变得简单直观。

接下来我将带你使用 Framer Motion 实现一个选中样式平滑过渡的案例。

案例

基本环境

本案例基于 Vite + React + TypeScript + TailwindCSS 搭建。TailwindCSS 不是必须的,我主要是为了不写 CSS 样式,若想实现和本案例相同的效果,可以安装一下 TailwindCSS。

基本页面

基本页面比较简单,主要就是渲染不同的导航链接,当点击时设置选中的导航,在选中的导航内渲染一个 span 用于显示选中样式,App.tsx

tsx 复制代码
import { useState } from "react";

const navs = [
  {
    name: "Home",
    href: "#home",
  },
  {
    name: "About",
    href: "#about",
  },
  {
    name: "Contact",
    href: "#contact",
  },
];

function App() {
  const [activeNav, setActiveNav] = useState("#home");

  return (
    <div className="mx-auto grid h-full max-w-2xl place-items-center space-y-4 py-4">
      <div className="space-y-8">
        <ul className="flex gap-2">
          {navs.map((nav, index) => (
            <li key={index} className="relative">
              <a
                href={nav.href}
                className="block rounded-md px-4 py-2 text-sm font-medium"
                onClick={() => {
                  setActiveNav(nav.href);
                }}
              >
                {nav.name}

                {nav.href === activeNav && (
                  <span className="absolute inset-0 -z-10 rounded-full bg-gray-100"></span>
                )}
              </a>
            </li>
          ))}
        </ul>

        <ul className="flex flex-col gap-2">
          {navs.map((nav, index) => (
            <li key={index} className="relative">
              <a
                href={nav.href}
                className="block rounded-md px-4 py-1 text-sm font-medium hover:bg-gray-100"
                onClick={() => {
                  setActiveNav(nav.href);
                }}
              >
                {nav.name}

                {nav.href === activeNav && (
                  <span className="absolute inset-y-0 left-0 w-1 rounded-full bg-gray-200"></span>
                )}
              </a>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;
  1. navs 数组:定义了导航链接的数据。
  2. activeNav 状态:存储当前选中的导航项。
  3. 导航列表:通过<ul>元素创建垂直和水平的导航条目。
  4. 点击事件处理:更新activeNav状态以高亮显示当前选中导航。
  5. 条件渲染:根据activeNav状态在选中的导航下显示指示标识。

此时已经完成了案例的基本样式,通过点击发现此时还没有任何动画,选中之间的过渡比较生硬。

npm 安装 Framer Motion:

bash 复制代码
npm install framer-motion

使用 pnpm:

bash 复制代码
pnpm add framer-motion

修改 app.tsx

tsx 复制代码
import { motion } from "framer-motion";

<motion.span
	className="absolute inset-0 -z-10 rounded-full bg-gray-100"
	layoutId="activeNav"
	transition={{
		type: "spring",
		stiffness: 380,
		damping: 30,
	}}
></motion.span>

<motion.span
	className="absolute inset-y-0 left-0 w-1 rounded-full bg-gray-200"
	layoutId="activeNav2"
	transition={{
		type: "spring",
		stiffness: 380,
		damping: 30,
	}}
></motion.span>

引入 framer-motion,然后把设置选中样式的 span 改为 motion.span,添加 layoutIdtransition 属性,动画设置为 spring 弹簧动画。

layoutId 用来创建动画以平滑地过渡共享元素的布局变化。
transition 属性用来定义动画的持续时间、延迟、缓动函数(如线性、弹性)、循环次数等特性。
stiffness 这个参数影响弹簧的硬度。一个更高的刚度值意味着弹簧更硬,它会更快地回到它的起始位置,导致动画更快地开始并且拥有一个更小的震荡周期。简言之,刚度越大,弹簧越"紧",动画运动越快。
damping 这个参数影响弹簧动画的阻尼效果,也就是减震效果。一个更高的阻尼值会导致弹簧运动时震荡得更少,从而更快地稳定下来。如果阻尼值设置得很低,动画会在达到静止状态之前在结束位置附近做较多的震荡。

完整代码

tsx 复制代码
import { useState } from "react";

import { motion } from "framer-motion";

const navs = [
  {
    name: "Home",
    href: "#home",
  },
  {
    name: "About",
    href: "#about",
  },
  {
    name: "Contact",
    href: "#contact",
  },
];

function App() {
  const [activeNav, setActiveNav] = useState("#home");

  return (
    <div className="mx-auto grid h-full max-w-2xl place-items-center space-y-4 py-4">
      <div className="space-y-8">
        <ul className="flex gap-2">
          {navs.map((nav, index) => (
            <li key={index} className="relative">
              <a
                href={nav.href}
                className="block rounded-md px-4 py-2 text-sm font-medium"
                onClick={() => {
                  setActiveNav(nav.href);
                }}
              >
                {nav.name}

                {nav.href === activeNav && (
                  <motion.span
                    className="absolute inset-0 -z-10 rounded-full bg-gray-100"
                    layoutId="activeNav"
                    transition={{
                      type: "spring",
                      stiffness: 380,
                      damping: 30,
                    }}
                  ></motion.span>
                )}
              </a>
            </li>
          ))}
        </ul>

        <ul className="flex flex-col gap-2">
          {navs.map((nav, index) => (
            <li key={index} className="relative">
              <a
                href={nav.href}
                className="block rounded-md px-4 py-1 text-sm font-medium hover:bg-gray-100"
                onClick={() => {
                  setActiveNav(nav.href);
                }}
              >
                {nav.name}

                {nav.href === activeNav && (
                  <motion.span
                    className="absolute inset-y-0 left-0 w-1 rounded-full bg-gray-200"
                    layoutId="activeNav2"
                    transition={{
                      type: "spring",
                      stiffness: 380,
                      damping: 30,
                    }}
                  ></motion.span>
                )}
              </a>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;
相关推荐
王哈哈^_^1 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie1 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic2 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿2 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具3 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
清灵xmf3 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据3 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161773 小时前
防抖函数--应用场景及示例
前端·javascript
334554324 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test4 小时前
js下载excel示例demo
前端·javascript·excel