React动画实现方案Framer Motion让页面自己动起来

 更新时间:2022年10月28日 15:33:48   作者:马睿不想说话  
这篇文章主要为大家介绍了React动画实现方案Framer Motion让页面自己动起来,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

相信很多前端同学都或多或少和动画打过交道。有的时候是产品想要的过度效果;有的时候是UI想要的酷炫动画。但是有没有人考虑过,是不是我们的页面上面的每一次变化,都可以像是自然而然的变化;是不是每一次用户点击所产生的交互,都可以在页面上活过来呢?

欢迎你打开了新的前端动画世界——《Framer Motion》

效果体验

这里,我在framer官网上面给大家录制了一下大概的使用效果。

在我们的常规认知中,实现这样的效果其实需要很多的css来实现,或者说需要我们进行大量的定制化逻辑编写。但是如果我们使用framer motion的话,只需要如下代码:

import { AnimatePresence, motion } from 'framer-motion';
const [selectedId, setSelectedId] = useState(null);
{items.map(item => (
  <motion.div layoutId={item.id} onClick={() => setSelectedId(item.id)}>
    <motion.h5>{item.subtitle}</motion.h5>
    <motion.h2>{item.title}</motion.h2>
  </motion.div>
))}
<AnimatePresence>
  {selectedId && (
    <motion.div layoutId={selectedId}>
      <motion.h5>{item.subtitle}</motion.h5>
      <motion.h2>{item.title}</motion.h2>
      <motion.button onClick={() => setSelectedId(null)} />
    </motion.div>
  )}
</AnimatePresence>

从上面的实现我们可以看出,framer-motion可以说是我们在用react动效开发过程中的必备利器。那么接下来,我给大家简单介绍一些framer motion的基础用法。

快速开始

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

安装

从npm安装framer-motion

npm install framer-motion

输入

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

import { motion } from "framer-motion"
export const MyComponent = ({ isVisible }) => (
    <motion.div animate={{ opacity: isVisible ? 1 : 0 }} />
)

使用方式

Framer motion的核心API是motion的组件。每个HTMLSVG标签都有对应的motion组件。

他们渲染的结果与对应的原生组件完全一致,并在其之上增加了一些动画和手势相关的props

比如:

<motion.div />
<motion.span />
<motion.h1 />
<motion.svg />
...

示例

比如我们现在想要实现一个侧边栏效果。

节点的挂载与卸载(mount、unmount)

如果我们自己来实现的话,可能要考虑它的keyframe,它的初始状态与最终的css样式。那么如果用framer-motion来如何实现呢?

首先我们来设计一个会动的按钮Icon:

import * as React from "react";
import { motion } from "framer-motion";
const Path = props => (
  <motion.path
    fill="transparent"
    strokeWidth="3"
    stroke="hsl(0, 0%, 18%)"
    strokeLinecap="round"
    {...props}
  />
);
const MenuToggle = ({ toggle }) => (
  <button onClick={toggle}>
    <svg width="23" height="23" viewBox="0 0 23 23">
      <Path
        variants={{
        closed: { d: "M 2 2.5 L 20 2.5" },
        open: { d: "M 3 16.5 L 17 2.5" }
        }}
      />
      <Path
        d="M 2 9.423 L 20 9.423"
        variants={{
        closed: { opacity: 1 },
        open: { opacity: 0 }
        }}
        transition={{ duration: 0.1 }}
      />
      <Path
        variants={{
        closed: { d: "M 2 16.346 L 20 16.346" },
        open: { d: "M 3 2.5 L 17 16.346" }
        }}
      />
    </svg>
  </button>
);

接下来,就由这个按钮来控制侧边栏的展示(mount)与隐藏(unmount):

import * as React from "react";
import { useRef } from "react";
import { motion, useCycle } from "framer-motion";
import { useDimensions } from "./use-dimensions";
const sidebar = {
  open: (height = 1000) => ({
    clipPath: `circle(${height * 2 + 200}px at 40px 40px)`,
    transition: {
      type: "spring",
      stiffness: 20,
      restDelta: 2
    }
  }),
  closed: {
    clipPath: "circle(30px at 40px 40px)",
    transition: {
      delay: 0.5,
      type: "spring",
      stiffness: 400,
      damping: 40
    }
  }
};
export const Example = () => {
  const [isOpen, toggleOpen] = useCycle(false, true);
  const containerRef = useRef(null);
  const { height } = useDimensions(containerRef);
  return (
    <motion.nav
      initial={false}
      animate={isOpen ? "open" : "closed"}
      custom={height}
      ref={containerRef}
    >
      <motion.div className="background" variants={sidebar} />
      <MenuToggle toggle={() => toggleOpen()} />
    </motion.nav>
  );
};

也就是说,其实我们更多需要做的事情,从思考如何设计各元素之间的css联动与keyframe书写变成了如何按照文档写好framer-motion的配置。哪个更轻松相信大家一目了然。

列表

侧边栏一般都是带有菜单的,那么我们是不是可以让这个侧边栏也有一个逐次出现的效果呢?就像这样:

这里我们是不是已经开始肌肉记忆般的计算延迟时间,思考如何进行整体效果的分配。那么如果这里我们使用frame motion,它的实现方式应该是怎么样的呢?

首先我们先来进行单个Item的封装:

import * as React from "react";
import { motion } from "framer-motion";
const variants = {
  open: {
    y: 0,
    opacity: 1,
    transition: {
      y: { stiffness: 1000, velocity: -100 }
    }
  },
  closed: {
    y: 50,
    opacity: 0,
    transition: {
      y: { stiffness: 1000 }
    }
  }
};
const colors = ["#FF008C", "#D309E1", "#9C1AFF", "#7700FF", "#4400FF"];
export const MenuItem = ({ i }) => {
  const style = { border: `2px solid ${colors[i]}` };
  return (
    <motion.li
      variants={variants}
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.95 }}
    >
      <div className="icon-placeholder" style={style} />
      <div className="text-placeholder" style={style} />
    </motion.li>
  );
};

然后我们在已封装Item的基础上,再进行整个菜单的封装:

import * as React from "react";
import { motion } from "framer-motion";
const itemIds = [0, 1, 2, 3, 4];
const variants = {
  open: {
    transition: { staggerChildren: 0.07, delayChildren: 0.2 }
  },
  closed: {
    transition: { staggerChildren: 0.05, staggerDirection: -1 }
  }
};
export const Navigation = () => (
  <motion.ul variants={variants}>
    {itemIds.map(i => (
      <MenuItem i={i} key={i} />
    ))}
  </motion.ul>
);

没错,动画!就是这么简单!

更多API

更详细、更具体的功能大家可以参考下官方的使用文档,我就不在这里一一列举了。

美中不足

其实不难看出,不论是实现的效果,还是使用方式,对于前端的同学来说framer-motion都是非常友好的工具。这一点从npmWeekly Downloads以及githubstar上面都不难看出。

但是目前也有一个问题,那就是包的体积问题。

这个包的大小对于部分的系统来说,还是不够友好。这也是很多人不选择使用它的原因。

以上就是React动画实现方案Framer Motion让页面自己动起来的详细内容,更多关于React 动画 Framer Motion的资料请关注脚本之家其它相关文章!

相关文章

  • react-router v6实现动态路由实例

    react-router v6实现动态路由实例

    这篇文章主要为大家介绍了react-router v6实现动态路由实例详解,<BR>有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • React函数组件与类的区别有哪些

    React函数组件与类的区别有哪些

    函数式组件的基本意义就是,组件实际上是一个函数,不是类,下面这篇文章主要给大家介绍了关于React中函数组件与类的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-10-10
  • React中传递组件的三种方式小结

    React中传递组件的三种方式小结

    通过传递组件,我们可以将复杂组件内部的一部分 UI 交由外部组件来控制渲染,这也是控制反转(Inversion of Control)的一种体现,在 React 中,我们可以通过三种方式来传递组件,本文就来给大家述说这三种方式,需要的朋友可以参考下
    2023-07-07
  • React Native 混合开发多入口加载方式详解

    React Native 混合开发多入口加载方式详解

    这篇文章主要介绍了React Native 混合开发多入口加载方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • react中关于useCallback的用法

    react中关于useCallback的用法

    这篇文章主要介绍了react中关于useCallback的用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • React Hooks使用常见的坑

    React Hooks使用常见的坑

    React Hooks 是 React 16.8 引入的新特性,允许我们在不使用 Class 的前提下使用 state 和其他特性。接下来通过本文给大家分享React Hooks使用避坑指南,一起学习下吧
    2021-06-06
  • react-native使用react-navigation进行页面跳转导航的示例

    react-native使用react-navigation进行页面跳转导航的示例

    本篇文章主要介绍了react-native使用react-navigation进行页面跳转导航的示例,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • React中实现父组件调用子组件的三种方法

    React中实现父组件调用子组件的三种方法

    在React中,组件之间的通信是一个常见的需求,有时,我们需要从父组件调用子组件的方法,这可以通过几种不同的方式实现,需要的朋友可以参考下
    2024-04-04
  • react-native-tab-navigator组件的基本使用示例代码

    react-native-tab-navigator组件的基本使用示例代码

    本篇文章主要介绍了react-native-tab-navigator组件的基本使用示例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-09-09
  • React路由组件三种传参方式分析讲解

    React路由组件三种传参方式分析讲解

    本文主要介绍了React组件通信之路由传参(react-router-dom),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08

最新评论