页面出现的线性的动画,之前在刚开始重构 blog 时就想实现,不过因为当时比较忙,就暂时搁置了,最近有空,就还是使用 motion 库来实现一下。
需要实现的效果
页面元素依次出现,首先是过渡动画包括 opacity blur X 这三部分的变化,并且需要有一个 delay 的效果,让元素一个一个的出现。
实现思路
opacity blur X 这种变化,使用 motion 实现十分简单,甚至用原生 js 也很简单,问题在于 delay 的效果。页面有很多元素 甚至包括需要渲染的列表,如果一个一个添加恐怕是十分浪费时间。
花了一点时间仔细查了 motion 的文档,发现一个好东西 staggerChildren (文档) ,使用这个配合 variants 属性,可以轻松实现元素和子元素的依次出现。
代码
先新建一个 motionVariants.tsx 组件重复调用。在其中定义 containerVariants 和 itemVariants。
export const containerVariants = { hidden: { opacity: 0, filter: "blur(8px)", transform: "translateY(16px) translateZ(0)" }, visible: { opacity: 1, filter: "blur(0)", transform: "none", transition: { transform: { duration: 0.4, timeConstant: 750 }, opacity: { duration: 0.7, timeConstant: 350 }, filter: { duration: 0.8, timeConstant: 350 }, type: "tween", duration: 0.6, ease: [0.25, 0.3, 0.5, 1], delayChildren: 0, // staggerChildren: 0.12, // 每个子项之间的延迟时间 staggerChildren: 0.08 // 每个子项之间的延迟时间 } }};export const itemVariants = { hidden: { opacity: 0, filter: "blur(8px)", transform: "translateY(16px) translateZ(0)", transition: {} }, visible: { opacity: 1, filter: "blur(0)", transform: "none", transition: { transform: { duration: 0.2, timeConstant: 350 }, opacity: { duration: 0.4, timeConstant: 350 }, filter: { duration: 0.4, timeConstant: 350 }, duration: 0.4, ease: [0.25, 0.3, 0.5, 1] } }};在你的组件中添加效果
import { motion } from 'framer-motion'import { containerVariants, itemVariants } from '@/components/MyMotion' return ( <> <motion.div variants={containerVariants} initial="hidden" animate="visible"> <motion.div variants={itemVariants}> <h2>title</h2> </motion.div> <motion.div variants={itemVariants}> <p>body</p> </motion.div> <motion.div variants={itemVariants}> <p>link</p> </motion.div> </div> </> )}