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
的组件。每个HTML
和SVG
标签都有对应的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,让你的页面“自己”动起来相关推荐
- 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 ...
- React 动效 Framer motion,给你的页面添加一点动感
Framer motion的核心API是motion的组件.每个HTML和SVG标签都有对应的motion组件. 他们渲染的结果与对应的原生组件完全一致,并在其之上增加了一些动画和手势相关的props ...
- 直播App中Android酷炫礼物动画实现方案(上篇)
在当下移动直播火爆的年代,如果你曾经使用过移动端直播应用,相信会被里面那令人惊叹的礼物动画效果迷住,比如像下面这样的效果. 从开发人员的角度来看,这样的效果虽然漂亮,实现但却是一大挑战,除了要考虑编码 ...
- 成品app直播源码中Android酷炫礼物动画实现方案(上篇)
成品app直播源码中Android酷炫礼物动画实现方案(上篇) +在当下移动直播火爆的年代,如果你曾经使用过移动端直播应用,相信会被里面那令人惊叹的礼物动画效果迷住,比如像下面这样的效果. 从开发人员 ...
- react性能优化方案_React灵敏且性能卓越的Spray + Akka解决方案,以“在Java和Node.js中发挥并发性和性能”...
react性能优化方案 在我以前的文章中,我研究了一个虚拟的交易引擎,并将基于Java的阻止解决方案与基于Node.js的非阻止解决方案进行了比较. 在文章的结尾,我写道: 我怀疑随着Node.js的 ...
- react动画_动画键盘(第2部分):对WindowInset动画做出React
react动画 In the previous blog post, we covered all of the changes to the APIs related to going edge-t ...
- CV之IA:利用人工智能算法实现图像动画(以让古代皇帝画像以及古代四大美女画像动起来-来模仿偶像胡歌剧中角色表情动作为例-照片嗨起来)案例应用
CV之IA:利用人工智能算法实现图像动画(以让古代皇帝画像以及古代四大美女画像动起来-来模仿偶像胡歌剧中角色表情动作为例-照片嗨起来)案例应用 导读:本论文来自NeurIPS2019,该算法中主要采用 ...
- C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(二)让物体动起来②
第二种方法,CompositionTarget动画,官方描述为:CompositionTarget对象可以根据每个帧回调来创建自定义动画.其实直接点,CompositionTarget创建的动画是基于 ...
- 2019年,实现 React 动画的 5 种最常用方式
动画是 ReactJs 应用程序中一个热门话题,我们有很多方法可以创建不同类型的动画.例如,很多开发人员就喜欢使用 css 动画.但如果你想创建更复杂的动画,你可以关注 GreenSock .Gree ...
最新文章
- C语言面试算法题(一)
- Failed to download You must enable the openssl extension to download files via https
- Java黑皮书课后题第4章:*4.15(电话键盘)电话上的国际标准字母/数字映射如下所示。编写程序,提示用户输入一个小写或大写字母,然后显示对应数字。对于非字母输入,提示非法输入
- IDEA使用从Eclipse过来的快捷键
- 嵌入式linux开发业内各个常用开源项目git仓库地址大全
- 【数据结构与算法】二叉树结点最小深度求解算法
- python之(re)正则表达式下
- itest(爱测试) 3.3.7 发布,开源BUG 跟踪管理 敏捷测试管理软件
- 8个习惯让你减肥不用节食 - 生活至上,美容至尚!
- 台式计算机时间不能同步,电脑时间不能同步的原因和图文解决方法
- 修改判断名字重复,保证名字唯一
- 千帆竞发待东风――乱弹网络游戏广告
- js实现雪花飘落效果
- 第十四周学习周报20181210-20181216
- Matlab幂律变换及直方图均衡化
- forEach,$.each()以及$().each()的比较
- mac BigSur修改系统文件方法
- python猜单词游戏_Python小程序之猜单词游戏
- 根据血象化验单判断感冒类型
- 天梯赛的善良 (20 分)