本文系翻译,有删改,原文见阅读原文
“能快速看到编码效果”是很人选择从事前端岗位的初衷。
每个前端萌新都有个实现酷炫动效的理想。
使用React
技术栈如何才能快速实现酷炫动效?今天向大家推荐一个动效库 —— Framer motion
。
怎么用?
Framer motion
的核心API是motion
的组件。每个HTML
和SVG
标签都有对应的motion
组件。
他们渲染的结果与对应的原生组件完全一致,并在其之上增加了一些动画和手势相关的props
。
比如:
代码语言:javascript复制<motion.div />
<motion.span />
<motion.h1 />
<motion.svg />
mount动画
假设我们要实现一个组件mount
时的下降显现效果,需要使用motion
组件的initial
和animate
属性。
initial
定义组件的初始状态。animate
定义组件mount
时的动画效果。如果其值与initial
不同,则会产生过渡的动画效果。
import { motion } from "framer-motion"
<motion.div
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: 1, y: 0 }}
>
Hello World!
</motion.div>
Framer Motion
检测到initial
与animate
中有value
不同的key
,对这些key
执行过渡效果。
例子中y轴方向距离会从-50变为0,透明度从0变为1。
unmount动画
在做删除所选项或翻页时,组件unmount
时的动画效果很重要。
为了实现unmount
动画效果,需要将组件包裹在<AnimatePresence/>
内。
这是因为我们需要延迟组件unmount
的时机,这样才有时间展示消失动画。
就像initial
对应animate
的渐变,我们需要指定exit
属性,当组件unmount
时,会执行从animate
到exit
的动画效果。
import { motion } from "framer-motion"
<AnimatePresence>
<motion.div
exit={{ opacity: 0, y: -50 }}
initial={{ opacity: 0, y: -50 }}
animate={{ opacity: 1, y: 0 }}
>
Hello World!
</motion.div>
</AnimatePresence>
效果:
编排动画
Framer Motion
的一个强大功能是:通过variants
属性来编排不同组件的动效。
下面的代码通过variants
属性实现上文mount
时同样的效果。
const variants = {
visible: { opacity: 0, y: -50 },
hidden: { opacity: 1, y: 0 },
}
<motion.div initial="hidden" animate="visible" variants={variants} />
这里传给initial
和animate
的是字符串,其中hidden
字符串指代variants.hidden
对象。
这是varients
刻意要求的。当motion
组件有children
时,拥有animate
属性的子孙motion
组件也能响应同样的效果。
假设我们要实现如下效果:
每个卡片组件有偏移、渐入的mount
时动画,同时每个卡片组件在前一个卡片进入后的0.1秒后进入。
为了实现这个效果,我们先为卡片、容器组件实现对应的variants
:
const variants = {
// 容器对应的variants效果
container: {
},
// 卡片对应的variants效果
card: {
}
};
其中卡片有x轴的偏移和opacity
的改变:
const variants = {
container: {
},
card: {
initial: {
opacity: 0,
x: -50
},
animate: {
opacity: 1,
x: 0
}
}
};
容器通过animate.transition.staggerChildren
指明每个motion
子组件的过渡间隔时间:
const variants = {
container: {
animate: {
transition: {
staggerChildren: 0.1
}
}
},
card: {
initial: {
opacity: 0,
x: -50
},
animate: {
opacity: 1,
x: 0
}
}
};
对应组件:
代码语言:javascript复制
const StaggeredList = () => {
return (
<motion.div
initial="initial"
animate="animate"
variants={variants.container}
>
{new Array(5).fill("").map(() => {
return <Card />;
})}
</motion.div>
);
};
const Card = () => (
<motion.div
variants={variants.card}
>
Hello World!
</motion.div>
);
其他可选库
上文我们介绍了Framer motion
的基本使用。除此以外,React Spring[1]也是React
技术栈优秀的动效库。
Framer Motion
简单易懂,同时支持更多动画类型,如:
- 弹力
- 补间动画
- 惯性运动
他的缺点是缺少文档,并且某些属性对SVG
无效。
React Spring
是一个基于弹性力学的动画库。通过他,可以更灵活的实现Framer Motion
的所有效果。但是学习曲线很陡峭。
建议做复杂自定义动画时可以考虑(尤其是SVG
和3D
)。
参考资料
[1]
React Spring: https://www.react-spring.io/