前言

相信很多前端同学都或多或少和动画打过交道。有的时候是产品想要的过度效果;有的时候是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.pathfill="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"><Pathvariants={{closed: { d: "M 2 2.5 L 20 2.5" },open: { d: "M 3 16.5 L 17 2.5" }}}/><Pathd="M 2 9.423 L 20 9.423"variants={{closed: { opacity: 1 },open: { opacity: 0 }}}transition={{ duration: 0.1 }}/><Pathvariants={{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.navinitial={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.livariants={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都是非常友好的工具。这一点从npm的Weekly Downloads以及github的star上面都不难看出。

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

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

React动画实现方案之 Framer Motion,让你的页面“自己”动起来相关推荐

  1. framer x使用教程_如何使用Framer Motion将交互式动画和页面过渡添加到Next.js Web应用程序

    framer x使用教程 The web is vast and it's full of static websites and apps. But just because those apps ...

  2. React 动效 Framer motion,给你的页面添加一点动感

    Framer motion的核心API是motion的组件.每个HTML和SVG标签都有对应的motion组件. 他们渲染的结果与对应的原生组件完全一致,并在其之上增加了一些动画和手势相关的props ...

  3. 直播App中Android酷炫礼物动画实现方案(上篇)

    在当下移动直播火爆的年代,如果你曾经使用过移动端直播应用,相信会被里面那令人惊叹的礼物动画效果迷住,比如像下面这样的效果. 从开发人员的角度来看,这样的效果虽然漂亮,实现但却是一大挑战,除了要考虑编码 ...

  4. 成品app直播源码中Android酷炫礼物动画实现方案(上篇)

    成品app直播源码中Android酷炫礼物动画实现方案(上篇) +在当下移动直播火爆的年代,如果你曾经使用过移动端直播应用,相信会被里面那令人惊叹的礼物动画效果迷住,比如像下面这样的效果. 从开发人员 ...

  5. react性能优化方案_React灵敏且性能卓越的Spray + Akka解决方案,以“在Java和Node.js中发挥并发性和性能”...

    react性能优化方案 在我以前的文章中,我研究了一个虚拟的交易引擎,并将基于Java的阻止解决方案与基于Node.js的非阻止解决方案进行了比较. 在文章的结尾,我写道: 我怀疑随着Node.js的 ...

  6. react动画_动画键盘(第2部分):对WindowInset动画做出React

    react动画 In the previous blog post, we covered all of the changes to the APIs related to going edge-t ...

  7. CV之IA:利用人工智能算法实现图像动画(以让古代皇帝画像以及古代四大美女画像动起来-来模仿偶像胡歌剧中角色表情动作为例-照片嗨起来)案例应用

    CV之IA:利用人工智能算法实现图像动画(以让古代皇帝画像以及古代四大美女画像动起来-来模仿偶像胡歌剧中角色表情动作为例-照片嗨起来)案例应用 导读:本论文来自NeurIPS2019,该算法中主要采用 ...

  8. C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(二)让物体动起来②

    第二种方法,CompositionTarget动画,官方描述为:CompositionTarget对象可以根据每个帧回调来创建自定义动画.其实直接点,CompositionTarget创建的动画是基于 ...

  9. 2019年,实现 React 动画的 5 种最常用方式

    动画是 ReactJs 应用程序中一个热门话题,我们有很多方法可以创建不同类型的动画.例如,很多开发人员就喜欢使用 css 动画.但如果你想创建更复杂的动画,你可以关注 GreenSock .Gree ...

最新文章

  1. C语言面试算法题(一)
  2. Failed to download You must enable the openssl extension to download files via https
  3. Java黑皮书课后题第4章:*4.15(电话键盘)电话上的国际标准字母/数字映射如下所示。编写程序,提示用户输入一个小写或大写字母,然后显示对应数字。对于非字母输入,提示非法输入
  4. IDEA使用从Eclipse过来的快捷键
  5. 嵌入式linux开发业内各个常用开源项目git仓库地址大全
  6. 【数据结构与算法】二叉树结点最小深度求解算法
  7. python之(re)正则表达式下
  8. itest(爱测试) 3.3.7 发布,开源BUG 跟踪管理 敏捷测试管理软件
  9. 8个习惯让你减肥不用节食 - 生活至上,美容至尚!
  10. 台式计算机时间不能同步,电脑时间不能同步的原因和图文解决方法
  11. 修改判断名字重复,保证名字唯一
  12. 千帆竞发待东风――乱弹网络游戏广告
  13. js实现雪花飘落效果
  14. 第十四周学习周报20181210-20181216
  15. Matlab幂律变换及直方图均衡化
  16. forEach,$.each()以及$().each()的比较
  17. mac BigSur修改系统文件方法
  18. python猜单词游戏_Python小程序之猜单词游戏
  19. 根据血象化验单判断感冒类型
  20. 天梯赛的善良 (20 分)

热门文章

  1. 2016寒假读书笔记
  2. Android一键锁屏,去除锁屏密码
  3. Redis 的 RDB 和 AOF
  4. spoolsv.exe占cpu 99%的解决方法
  5. initrd和initramfs的区别
  6. cellpadding 与cellspace 属性
  7. 软件架构师需要什么能力?
  8. 极限学习机(Extreme Learning Machine, ELM)的训练与预测matlab仿真
  9. DH-UAP(大华统一应用开发平台)简介
  10. cesium实现流入迁徙图(仿echarts)(着色器)(cesium篇.52)