如何为Framer Motion动画添加条件控制,实现单卡片触发动画?
解决Framer Motion点击单张卡片仅触发该卡片动画的问题
我是React新手,制作了三张卡片并使用Framer Motion实现动画。我希望点击某一张卡片时仅该卡片触发动画,但目前点击任意卡片时三张卡片都会同时启动动画,请问如何为Framer Motion动画添加条件控制?
我的代码如下:
import "./styles.css"; import { useState,useEffect } from "react"; import { motion, useAnimationControls } from "framer-motion" export default function App() { const [elements,setElements]=useState(['one','two','three']) const controls = useAnimationControls() return ( <section className="App"> { elements.map((Element,index)=>( <motion.div key={index} animate={controls} onClick={()=>controls.start({ scale: 2 })}>{Element}</motion.div> )) } </section> ); }
核心问题原因
你当前的代码中所有卡片共用了同一个useAnimationControls控制器,所以点击任意卡片时,控制器会触发所有绑定它的motion组件执行动画。要实现单张卡片独立触发,需要让每个卡片拥有独立的动画控制逻辑。
方法一:用状态记录激活卡片索引(最简单方案)
通过useState记录当前被点击的卡片索引,每个卡片根据自身索引判断是否执行动画:
import "./styles.css"; import { useState } from "react"; import { motion } from "framer-motion" export default function App() { const [elements, setElements] = useState(['one','two','three']) const [activeIndex, setActiveIndex] = useState(null) return ( <section className="App"> { elements.map((Element, index) => ( <motion.div key={index} animate={activeIndex === index ? { scale: 2 } : { scale: 1 }} onClick={() => setActiveIndex(index)} > {Element} </motion.div> )) } </section> ); }
方法二:为每个卡片创建独立动画控制器(适合复杂动画)
如果需要更精细的动画控制(比如多阶段动画),可以给每个卡片单独生成控制器:
import "./styles.css"; import { useState, useMemo } from "react"; import { motion, useAnimationControls } from "framer-motion" export default function App() { const [elements, setElements] = useState(['one','two','three']) // 为每个元素生成独立的动画控制器 const controlsList = useMemo(() => elements.map(() => useAnimationControls()), [elements] ) return ( <section className="App"> { elements.map((Element, index) => { const controls = controlsList[index] return ( <motion.div key={index} animate={controls} onClick={() => controls.start({ scale: 2 })} > {Element} </motion.div> ) }) } </section> ); }
方法三:用Variants结合状态控制(适合复用动画配置)
如果需要复用多组动画状态,可以定义Variants来管理:
import "./styles.css"; import { useState } from "react"; import { motion } from "framer-motion" // 定义动画状态集合 const cardVariants = { inactive: { scale: 1 }, active: { scale: 2 } } export default function App() { const [elements, setElements] = useState(['one','two','three']) const [activeIndex, setActiveIndex] = useState(null) return ( <section className="App"> { elements.map((Element, index) => ( <motion.div key={index} variants={cardVariants} initial="inactive" animate={activeIndex === index ? "active" : "inactive"} onClick={() => setActiveIndex(index)} > {Element} </motion.div> )) } </section> ); }
内容的提问来源于stack exchange,提问作者ABIDI MarWen
相关产品推荐
相关产品推荐

