本文系翻译,有删改,原文见这里
“能快速看到编码效果”是很人选择从事前端岗位的初衷。
每个前端萌新都有个实现酷炫动效的理想。
使用React技术栈如何才能快速实现酷炫动效?今天向大家推荐一个动效库 —— Framer motion。
怎么用?
Framer motion的核心API是motion的组件。每个HTML和SVG标签都有对应的motion组件。
他们渲染的结果与对应的原生组件完全一致,并在其之上增加了一些动画和手势相关的props。
比如:
<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
}
}
};
对应组件:
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也是React技术栈优秀的动效库。
Framer Motion简单易懂,同时支持更多动画类型,如:
-
弹力
-
补间动画
-
惯性运动
他的缺点是缺少文档,并且某些属性对SVG无效。
React Spring是一个基于弹性力学的动画库。通过他,可以更灵活的实现Framer Motion的所有效果。但是学习曲线很陡峭。
建议做复杂自定义动画时可以考虑(尤其是SVG和3D)。