如何为Framer Motion的useAnimate钩子设置初始值
问题:useAnimate结合useInView时如何设置初始值避免元素跳变?
当使用motion组件的initial属性时,我们可以直接定义元素的初始动画状态:
<motion.div initial={{ x: "100%" }} animate={{ x: "calc(100vw - 50%)" }} />
但在结合useAnimate与useInView钩子实现滚动触发动画时,如下代码会导致元素在动画开始前从0跳至100的初始位置:
const [scope, animate] = useAnimate(); const isInView = useInView(scope, { once: true, amount: 0.8 }); useEffect(() => { if (isInView) { animate('.anim-up', { y: [100, 0] }, { duration: 1, delay: stagger(0.15) }) } }, [isInView]);
请问该如何正确设置初始值?
解决方法
1. 预先通过CSS设置初始状态
给目标元素添加初始的transform样式,让元素默认处于动画起始位置,避免跳变:
.anim-up { transform: translateY(100px); }
或者直接使用内联样式:
<div className="anim-up" style={{ transform: "translateY(100px)" }}> {/* 元素内容 */} </div>
2. 用useAnimate设置瞬时初始状态
在组件挂载时,通过useAnimate将元素设置到初始位置,设置duration: 0让状态瞬间生效:
const [scope, animate] = useAnimate(); const isInView = useInView(scope, { once: true, amount: 0.8 }); // 挂载时设置初始位置 useEffect(() => { animate('.anim-up', { y: 100 }, { duration: 0 }); }, []); // 进入视口后执行动画 useEffect(() => { if (isInView) { animate('.anim-up', { y: 0 }, { duration: 1, delay: stagger(0.15) }); } }, [isInView]);
3. 结合motion组件的initial属性(推荐方案)
如果目标元素是motion组件,直接用initial属性定义初始状态,再通过useAnimate触发动画:
import { motion, useAnimate, useInView } from "framer-motion"; import { stagger } from "framer-motion/dom"; const YourComponent = () => { const [scope, animate] = useAnimate(); const isInView = useInView(scope, { once: true, amount: 0.8 }); useEffect(() => { if (isInView) { animate('.anim-up', { y: 0 }, { duration: 1, delay: stagger(0.15) }); } }, [isInView]); return ( <div ref={scope}> <motion.div className="anim-up" initial={{ y: 100 }}> {/* 元素内容 */} </motion.div> {/* 其他需要动画的元素 */} </div> ); };
内容的提问来源于stack exchange,提问作者leon
相关产品推荐
相关产品推荐

