ขอแนะนำ Framer Motion

เผยแพร่แล้ว: 2022-03-10
สรุปด่วน ↬ แอนิเมชั่นเมื่อทำถูกต้องจะทรงพลัง อย่างไรก็ตาม การสร้างแอนิเมชั่นที่สะดุดตาด้วย CSS อาจเป็นเรื่องยาก Framer Motion มาถึงแล้ว ด้วย Framer Motion คุณไม่จำเป็นต้องเป็นผู้เชี่ยวชาญ CSS เพื่อสร้างแอนิเมชั่นที่สวยงาม Framer Motion มอบแอนิเมชั่นพร้อมสำหรับการผลิตและ API ระดับต่ำที่เราสามารถโต้ตอบด้วยเพื่อรวมแอนิเมชั่นเหล่านี้เข้ากับแอปพลิเคชันของเรา

ในบทความนี้ เราจะมาดูรายละเอียดกันว่า Framer Motion ช่วยเราในการสร้างแอนิเมชั่นที่ยอดเยี่ยมได้อย่างไร เราจะเรียนรู้ว่าองค์ประกอบการเคลื่อนไหวทำงานอย่างไร และเรียนรู้วิธีเชื่อมโยงแอนิเมชั่นเข้าด้วยกัน เราจะมาดูวิธีการสร้างแอนิเมชั่นการสั่งการด้วยท่าทาง หมดเวลา และเลื่อนด้วย Framer Motion ระหว่างทาง เราจะใช้สิ่งที่เราเรียนรู้เพื่อสร้างแอปพลิเคชันสาธิตห้ารายการที่ฉันตั้งค่าเพื่อแสดงให้เราเห็นว่าเราจะผสานรวม Framer Motion เข้ากับแอปพลิเคชันในโลกแห่งความเป็นจริงได้อย่างไร

บทช่วยสอนนี้จะเป็นประโยชน์กับผู้อ่านที่สนใจในการรวมแอนิเมชั่นในแอปพลิเคชัน React ของพวกเขา

หมายเหตุ: บทความนี้ต้องการความเข้าใจพื้นฐานเกี่ยวกับ React และ CSS

Framer Motion คืออะไร?

Framer Motion เป็นไลบรารีแอนิเมชั่นที่ทำให้การสร้างแอนิเมชั่นเป็นเรื่องง่าย API แบบง่ายช่วยให้เราสรุปความซับซ้อนเบื้องหลังแอนิเมชั่น และช่วยให้เราสร้างแอนิเมชั่นได้อย่างง่ายดาย

ส่วนประกอบการเคลื่อนไหว

สิ่งเหล่านี้คือองค์ประกอบสำคัญของการเคลื่อนไหว Framer องค์ประกอบการเคลื่อนไหวถูกสร้างขึ้นโดยนำหน้า motion ไปยังองค์ประกอบ HTML และ SVG ปกติของคุณ (เช่น motion.h1 ) ส่วนประกอบการเคลื่อนไหวสามารถรับอุปกรณ์ประกอบฉากได้หลายแบบ โดยอุปกรณ์พื้นฐานคืออุปกรณ์ประกอบฉาก animate อุปกรณ์ประกอบฉากนี้ใช้วัตถุที่เรากำหนดคุณสมบัติขององค์ประกอบนั้นที่เราต้องการให้เคลื่อนไหว คุณสมบัติที่เรากำหนดจะเคลื่อนไหวเมื่อส่วนประกอบเชื่อมต่อใน DOM

มาทำให้ข้อความ h1 เคลื่อนไหวโดยใช้ Framer Motion ขั้นแรก เราติดตั้งไลบรารี framer-motion และนำเข้า motion

 npm i framer-motion import { motion } from 'framer-motion';

จากนั้นเราแปลง h1 เป็นองค์ประกอบการเคลื่อนไหว

 <motion.h1 animate={{x: 20, y: -20}}> This is a motion component </motion.h1>

ซึ่งจะทำให้ h1 เลื่อนไปทางขวา 20px และเลื่อนขึ้น 20px เมื่อโหลดขึ้น เมื่อไม่ได้เพิ่มหน่วย การคำนวณจะทำโดยใช้พิกเซล อย่างไรก็ตาม คุณสามารถตั้งค่าหน่วยที่ต้องการให้คำนวณได้อย่างชัดเจน animate={{x: "20rem", y: "-20rem"}}>

เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

โดยค่าเริ่มต้น ส่วนประกอบการเคลื่อนไหวจะเคลื่อนไหวจากสถานะที่กำหนดไว้ตั้งแต่สไตล์ไปจนถึงองค์ประกอบในพร็อพ animate อย่างไรก็ตาม หากเราต้องการ เราสามารถจี้และกำหนดสถานะแอนิเมชั่นเริ่มต้นของส่วนประกอบโดยใช้อุปกรณ์ประกอบฉาก initial แม้ว่าพร็อพ animate จะใช้เพื่อกำหนดพฤติกรรมของส่วนประกอบเมื่อเชื่อมต่อ พร็อพ initial จะกำหนดลักษณะการทำงานก่อนที่จะเมาต์

ถ้าเราต้องการให้ h1 เข้ามาทางซ้าย เราควบคุมมันโดยใช้เสาตั้งต้น

 <motion.h1 initial={{x: -1000}} animate={{x: 20}}> This is a motion component </motion.h1>

ตอนนี้ เมื่อ h1 ขึ้น มันจะเลื่อนเข้ามาจากด้านซ้าย

เราไม่ได้จำกัดอยู่แค่แอนิเมชั่นเดียว เราสามารถกำหนดชุดของแอนิเมชั่นที่เรียกว่า keyframes ในอาร์เรย์ของค่าต่างๆ แต่ละค่าจะได้รับภาพเคลื่อนไหวตามลำดับ

 <motion.h1 initial={{x: -1000}} animate={{x: [20, 50, 0, -70, 40] }}> This is a motion component </motion.h1>

พร็อพ transition ช่วยให้เราสามารถกำหนดว่าแอนิเมชั่นเกิดขึ้นได้อย่างไร ด้วยเหตุนี้ เราจึงกำหนดว่าค่าต่างๆ จะเคลื่อนไหวจากสถานะหนึ่งไปอีกสถานะหนึ่งอย่างไร เหนือสิ่งอื่นใด เราสามารถกำหนด duration delay และ type ของแอนิเมชั่นโดยใช้อุปกรณ์ประกอบฉากนี้

 <motion.h1 initial={{ x: -1000 }} animate={{ x: 0 }} transition={{ type: "tween", duration: "2", delay: "1" }}> This is a motion component </motion.h1>

สมมติว่าเราต้องทำให้องค์ประกอบการเคลื่อนไหวหลาย ๆ เคลื่อนไหวพร้อมๆ กัน เช่นในข้อมูลโค้ดด้านล่าง

 <div className="App"> <motion.h1 initial={{ x: -1000 }} animate={{ x: 0 }} transition={{ type: "tween", duration: "2", delay: "1" }}> This is a motion h1 </motion.h1> <motion.h2 initial={{ y: -1000 }} animate={{ y: 0 }} transition={{ type: "tween", duration: "1", delay: ".4" }}>This is a motion h2 </motion.h2> <motion.h3 initial={{ x: 100, opacity: 0 }} animate={{ x: 0, opacity: 1 }}> This is a motion h3 </motion.h3> <motion.h4 initial={{ scale: 0.7 }} animate={{ scale: 1.7 }} transition={{ type: "tween", duration: "2", delay: "1" }}> This is a motion h4 </motion.h4> </div>

แม้ว่าจะใช้งานได้ แต่ variants ประกอบใน Framer Motion ช่วยให้เราสามารถแยกคำจำกัดความของแอนิเมชั่นของเราออกเป็นอ็อบเจ็กต์ Variation variants ไม่เพียงแต่ทำให้โค้ดของเราสะอาดขึ้น แต่ยังช่วยให้เราสร้างแอนิเมชั่นที่ทรงพลังและซับซ้อนยิ่งขึ้นอีกด้วย

การแยกคำจำกัดความของแอนิเมชั่นของเราออกเป็นอ็อบเจ็กต์ตัวแปร เรามีสิ่งนี้:

 const H1Variants = { initial: { x: -1000 }, animate: { x: 0 }, transition: { type: "tween", duration: 2, delay: 1 } } const H2Variants = { initial: { y: -1000 }, animate: { y: 0 }, transition: { type: "tween", duration: 1, delay: .4 } } const H3Variants = { initial:{ x: 100, opacity: 0 }, animate:{ x: 0, opacity: 1 } } const H4Variants = { initial:{ scale: 0.7 }, animate:{ scale: 1.7 }, transition:{ type: "tween", duration: "2", delay: "1" } }

แทนที่จะส่งคำจำกัดความของแอนิเมชั่นไปยังอุปกรณ์ประกอบฉาก initial และอุปกรณ์ animate โดยตรงของคอมโพเนนต์ เราแยกคำจำกัดความเหล่านี้ออกเป็นออบเจ็กต์ตัวแปรแบบสแตนด์อโลน ในออบเจ็กต์ตัวแปร เรากำหนดชื่อตัวแปรที่อธิบายชื่อของแอนิเมชั่นแต่ละรายการเป็นรายละเอียดปลีกย่อย

 <div className="App"> <motion.h1 variants={H1Variants} initial='initial' animate='animate' > This is a motion h1 </motion.h1> <motion.h2 variants={H2Variants} initial='initial' animate='animate' > This is a motion h2 </motion.h2> <motion.h3 variants={H3Variants} initial='initial' animate='animate' > This is a motion h3 </motion.h3> <motion.h4 variants={H4Variants} initial='initial' animate='animate' > This is a motion h4 </motion.h4> </div>

ในอุปกรณ์ประกอบฉาก variants เราจะส่งต่อชื่อของวัตถุที่แปรผันสำหรับองค์ประกอบการเคลื่อนไหวแต่ละอย่าง จากนั้นจึงส่งต่อภาพเคลื่อนไหวไปยังอุปกรณ์ประกอบฉาก initial และอุปกรณ์ประกอบฉากที่ animate

เราสามารถใช้การตั้งค่าปัจจุบันของเรากับตัวแปรเพิ่มเติมเพื่อลดการซ้ำซ้อน เมื่อใช้ตัวแปร เราสามารถเผยแพร่แอตทริบิวต์แอนิเมชันลงผ่าน DOM จากคอมโพเนนต์การเคลื่อนไหวหลัก เพื่อให้ใช้งานได้ เราสร้างตัวแปรสำหรับ parent motion.div ที่มีชื่อแอนิเมชั่นที่คล้ายกันในออบเจ็กต์ตัวแปรเป็นลูก เมื่อทำเช่นนี้ เราจะไม่ต้องส่งชื่อแอนิเมชัน' ไปยังคอมโพเนนต์ย่อยแต่ละคอมโพเนนต์ เบื้องหลังองค์ประกอบหลักจัดการให้เรา

 const ContainerVariants = { initial: {}, animate: {} }; const H1Variants = { initial: { x: -1000 }, animate: { x: 0 }, transition: { type: "tween", duration: 2, delay: 1 } }; //more variants below <motion.div className="App" variants={ContainerVariants} initial="initial" animate="animate" > <motion.h1 variants={H1Variants}>This is a motion h1</motion.h1> <motion.h2 variants={H2Variants}>This is a motion h2</motion.h2> <motion.h3 variants={H3Variants}>This is a motion h3</motion.h3> <motion.h4 variants={H4Variants}>This is a motion h4</motion.h4> </motion.div>

ตอนนี้เรามีรหัสที่สะอาดกว่าโดยไม่มีการซ้ำซ้อน เราเปลี่ยน div คอนเทนเนอร์เป็นองค์ประกอบการเคลื่อนไหวเพื่อให้เราสามารถส่งผ่านในอ็อบเจ็กต์ ContainerVariants ที่เรากำหนดได้ เนื่องจากเราไม่ได้กำหนดแอนิเมชั่นใดๆ บนคอนเทนเนอร์ เราจึงส่งอ็อบเจ็กต์ว่างไปยัง initial และ animate ชื่อแอนิเมชั่นของคุณต้องเหมือนกันในทุกอ็อบเจ็กต์ตัวแปรเพื่อให้การขยายพันธุ์ทำงาน

ตอนนี้เราเข้าใจพื้นฐานของ Framer Motion แล้ว มาเริ่มสร้างแอปพลิเคชันสาธิต 5 แอปพลิเคชันกันเลย

ร้านไอคอน

เราสามารถสร้างแอนิเมชั่นแบบโต้ตอบตามท่าทางได้ ปัจจุบันคอมโพเนนต์การเคลื่อนไหวสามารถฟังการตรวจจับท่าทางสัมผัส การแตะ เลื่อน และลากได้ เราจะสร้างแอพ Icon Shop นี้โดยใช้ whileHover prop

ส่วนประกอบ

  • App.js : นี้เก็บข้อความหัวเรื่อง
  • Card.jsx : ที่นี่ เรากำหนดภาพเคลื่อนไหวสำหรับการ์ดไอคอน
  • CardContainer.jsx : เรานำเข้าและวนซ้ำไอคอนต่างๆ
  • styles.js : สร้าง จัดรูปแบบ และส่งออกส่วนประกอบการเคลื่อนไหว ฉันใช้ส่วนประกอบที่มีสไตล์เพื่อจัดสไตล์ส่วนประกอบ

มาเริ่มกันที่ App.js

 import { H1, H2 } from "./Styles"; import CardContainer from "./CardContainer"; return ( <div> <H1 initial={{ y: -100 }} animate={{ y: 0, transition: { delay: 1 } }}> Icon Shop </H1> <H2 initial={{ x: -1000 }} animate={{ x: 0, transition: { delay: 1 } }}> Hover over the cards to see the motion magic </H2> <CardContainer /> </div> );

เรานำเข้าส่วนประกอบการเคลื่อนไหว H1 และ H2 ที่เราสร้างขึ้นในไฟล์ Styles.js เนื่องจากเป็นส่วนประกอบในการเคลื่อนไหว เราจึงใช้อุปกรณ์ประกอบฉาก initial และ animate เพื่อกำหนดพฤติกรรมก่อนและเมื่อติดตั้ง ที่นี่ เรายังนำเข้าและแสดงองค์ประกอบ CardContiner

ตอนนี้ CardContainer.js

 import { Container } from "./Styles"; import Card from "./Card"; import { ReactComponent as AddIcon } from "./assets/add.svg"; import { ReactComponent as AirplaneIcon } from "./assets/airplane.svg"; import { ReactComponent as AlarmIcon } from "./assets/alarm.svg"; //more svg imports below... const icons = [ <AddIcon />, <AirplaneIcon />, <AlarmIcon />, //more icons below ]; const CardContainer = () => { return ( <Container initial={{ x: -1000 }} animate={{ x: 0 }}> {icons.map((icon) => ( <Card icon={icon} /> ))} </Container> ); };

ที่นี่ เรานำเข้า SVG ส่วนประกอบการเคลื่อนไหวของ Container และส่วนประกอบ Card

คล้ายกับ H1 และ H2 ใน App.js เรากำหนดแอนิเมชั่นของ Container โดยใช้อุปกรณ์ประกอบฉาก initial และ animate เมื่อโหลดมันจะสร้างเอฟเฟกต์เจ๋ง ๆ ของการเลื่อนเข้ามาจากด้านซ้ายของเบราว์เซอร์

ตอนนี้ Card.js

 import { CardBox, IconBox } from "./Styles"; const CardVariants = { beforeHover: {}, onHover: { scale: 1.1 } }; const IconVariants = { beforeHover: { opacity: 0, y: -50 }, onHover: { opacity: 1, y: 0, scale: 1.5, transition: { type: "tween" } } }; const Card = ({ icon }) => { console.log(icon); return ( <CardBox variants={CardVariants} initial="beforeHover" whileHover="onHover"> <IconBox variants={IconVariants}>{icon}</IconBox> </CardBox> ); };

ที่นี่ เราสร้างอ็อบเจ็กต์ที่แตกต่างสองรายการด้วยแอนิเมชั่น beforeHover และ onHover ในอ็อบเจ็กต์ CardVariants เราไม่ต้องการทำอะไรในตอนแรก ดังนั้น beforeHover จึงเป็นอ็อบเจกต์ว่าง onHover เราเพิ่มขนาดของกล่องการ์ด

ในอ็อบเจ็กต์ IconVariants เรากำหนดสถานะเริ่มต้นของ IconBox ใน beforeHover เราตั้งค่าความทึบเป็น 0 และดันขึ้นไป 50px จากนั้นใน onHover เราตั้งค่าความทึบกลับเป็น 1 ดันกลับไปที่ตำแหน่งเริ่มต้น และเปลี่ยนประเภทการเปลี่ยนเป็น tween จากนั้นเราจะส่งต่อตัวแปรต่างๆ ไปยังส่วนประกอบการเคลื่อนไหวที่เกี่ยวข้อง เราใช้การขยายพันธุ์ ดังนั้นเราจึงไม่จำเป็นต้องตั้งค่า initial และอุปกรณ์ประกอบฉาก animate ไปยังองค์ประกอบ IconBox อย่างชัดเจน

Navbar เคลื่อนไหว

เราจะสร้างองค์ประกอบการนำทางอย่างง่าย และเราจะดูว่าเราจะสร้างความสัมพันธ์ด้านเวลาระหว่างส่วนประกอบการเคลื่อนไหวของผู้ปกครองและเด็กได้อย่างไร

ส่วนประกอบ

  • App.js : นี้เก็บข้อความหัวเรื่อง
  • Styles.js : สร้าง จัดรูปแบบ และส่งออกส่วนประกอบการเคลื่อนไหว ส่วนประกอบต่างๆ ถูกจัดรูปแบบโดยใช้ส่วนประกอบที่มีสไตล์

มาดูไฟล์ App.js กัน

 import { Header, Nav, Link, SvgBox } from "./Styles"; function App() { const [isOpen, setIsOpen] = useState(false); const iconVariants = { opened: { rotate: 135 }, closed: { rotate: 0 } }; const menuVariants = { opened: { top: 0, transition: { when: "beforeChildren", staggerChildren: 0.5 } }, closed: { top: "-90vh" } }; const linkVariants = { opened: { opacity: 1, y: 50 }, closed: { opacity: 0, y: 0 } };

เราสร้างสถานะ isOpen ที่จะใช้ตรวจสอบว่า Navbar เปิดอยู่หรือไม่ เราสร้างอ็อบเจ็กต์ตัวแปร 3 รายการ, iconVariants , menuVariants และ linkVariants ซึ่งเรากำหนดแอนิเมชั่นสำหรับคอมโพเนนต์การเคลื่อนไหว SvgBox , Nav และ Link ตามลำดับ iconVariants ใช้เพื่อหมุน SvgBox 135deg เมื่อวางเมาส์เหนือ เราไม่จำเป็นต้องเพิ่ม "deg" ให้กับค่า ใน menuVariants เราควบคุมตำแหน่งบนสุดของ Nav เช่นเดียวกับที่คุณใช้คุณสมบัติ position ใน CSS เราสลับตำแหน่งบนสุดของการนำทางตาม isOpen Nav

ด้วยตัวแปร เราสามารถสร้างความสัมพันธ์ด้านเวลาระหว่างส่วนประกอบการเคลื่อนไหวของผู้ปกครองและเด็ก เรากำหนดความสัมพันธ์ระหว่าง Nav หลักและลูกของมัน Link โดยใช้คุณสมบัติ when ในออบเจกต์การเปลี่ยนแปลง ที่นี่ ตั้งค่าเป็น beforeChildren ดังนั้นแอนิเมชั่นขององค์ประกอบหลักจะเสร็จสิ้นก่อนที่แอนิเมชั่นของเด็กจะเริ่มขึ้น

การใช้คุณสมบัติ staggerChildren เราตั้งค่าลำดับเวลาสำหรับแต่ละลิงก์ แต่ละลิงก์จะใช้เวลา 0.5 วินาทีในการปรากฏขึ้นทีละรายการ สิ่งนี้จะสร้างสัญญาณภาพที่ดีเมื่อเปิด Nav ทาง ใน linkVariants เราทำให้ความทึบและตำแหน่งแนวตั้งของแต่ละลิงก์เคลื่อนไหว

 <div className="App"> <Header> <SvgBox variants={iconVariants} animate={isOpen ? "opened" : "closed"} onClick={() => setIsOpen(!isOpen)} > <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="https://www.w3.org/2000/svg" > <path d="M12 4C11.4477 4 11 4.44772 11 5V11H5C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13H11V19C11 19.5523 11.4477 20 12 20C12.5523 20 13 19.5523 13 19V13H19C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11H13V5C13 4.44772 12.5523 4 12 4Z" fill="#fff" /> </svg> </SvgBox> </Header> <Nav initial={false} variants={menuVariants} animate={isOpen ? "opened" : "closed"} > <Link variants={linkVariants}>home</Link> <Link variants={linkVariants}>about</Link> <Link variants={linkVariants}>gallery</Link> </Nav> </div>

ในที่นี้ เราส่งต่อตัวแปรต่างๆ ไปยังส่วนประกอบที่เกี่ยวข้องกัน ใน SvgBox เราสลับสถานะของ isOpen ทุกครั้งที่มีการคลิก จากนั้นทำให้เคลื่อนไหวตามเงื่อนไขตามสถานะ เช่นเดียวกับ SvgBox เราทำให้ Nav และ Link เคลื่อนไหวตามเงื่อนไขตามสถานะของ isOpen

โมดอลเคลื่อนไหว

เราจะสร้างองค์ประกอบโมดอลและเรียนรู้เกี่ยวกับ AnimatePresence ของ Framer Motion และวิธีที่ช่วยให้เราสร้างองค์ประกอบเคลื่อนไหวเมื่อพวกเขาออกจาก DOM

ส่วนประกอบ:

  • App.js : เราตั้งค่าสถานะ showModal ที่นี่
  • Modal.jsx : งานแอนิเมชั่นจริงเกิดขึ้นที่นี่
  • Styles.js : สร้าง จัดรูปแบบ และส่งออกส่วนประกอบการเคลื่อนไหว ส่วนประกอบต่างๆ ถูกจัดรูปแบบโดยใช้ส่วนประกอบที่มีสไตล์

มาดู App.js

 import { ToggleButton, Container } from "./Styles"; import Modal from "./Modal"; function App() { const [showModal, setShowModal] = useState(false); const toggleModal = () => { setShowModal(!showModal); }; return ( <Container> <ToggleButton initial={{ x: -700 }} animate={{ x: 0, transition: { duration: 0.5 } }} onClick={toggleModal} > Toggle Modal </ToggleButton> <Modal showModal={showModal} /> </Container> ); }

เราสร้างสถานะ showModal ที่จะใช้เพื่อแสดงโมดอลตามเงื่อนไข ฟังก์ชัน toggleModal จะสลับสถานะทุกครั้งที่มีการคลิก ToggleButton ToggleButton เป็นองค์ประกอบการเคลื่อนไหว ดังนั้นเราจึงสามารถกำหนดแอนิเมชั่นสำหรับมันได้ เมื่อติดตั้งแล้ว จะเลื่อนเข้าจากด้านซ้าย แอนิเมชั่นนี้ทำงานเป็นเวลา 0.5 วินาที นอกจากนี้เรายังส่งสถานะ showModal ไปยัง Modal ผ่านอุปกรณ์ประกอบฉาก

ตอนนี้ Modal.jsx

 import { AnimatePresence } from "framer-motion"; import { ModalBox, ModalContent, Container } from "./Styles"; <Container> <AnimatePresence> {showModal && ( <ModalBox initial={{ opacity: 0, y: 60, scale: 0.3 }} animate={{ opacity: 1, y: 0, scale: 1, transition: { type: "spring", stiffness: 300 } }} exit={{ opacity: 0, scale: 0.5, transition: { duration: 0.6 } }} > <ModalContent initial={{ y: -30, opacity: 0 }} animate={{ y: 0, opacity: 1, transition: { delay: 1 } }} > Modal content!!!! </ModalContent> </ModalBox> )} </AnimatePresence> </Container>

เรานำเข้า AnimatePresence จาก framer-motion ช่วยให้เราสามารถตั้งค่าแอนิเมชั่นการออกสำหรับส่วนประกอบเมื่อออกจาก DOM เราแสดง Modal ตามเงื่อนไขตามสถานะ showModal เรากำหนดแอนิเมชั่นสำหรับ ModalBox และ ModalContent ผ่านอุปกรณ์ประกอบฉาก initial และ animate มีพร็อพใหม่อยู่ที่นี่ด้วย exit การมี AnimatePresence เป็น wrapper ช่วยให้เราสามารถเพิ่มแอนิเมชั่นการออกไปยัง ModalBox ในอุปกรณ์ exit

เลื่อนนิเมชั่น

เราจะใช้ useAnimation hook และ react-intersection-observer ร่วมกันเพื่อสร้างแอนิเมชั่นที่เรียกด้วยการเลื่อน

ส่วนประกอบ

  • App.js : เราตั้งค่าแอนิเมชั่นสำหรับองค์ประกอบ Box และแสดงผลใน App
  • Styles.js : สร้าง จัดรูปแบบ และส่งออกส่วนประกอบการเคลื่อนไหว ส่วนประกอบต่างๆ ถูกจัดรูปแบบโดยใช้ส่วนประกอบที่มีสไตล์
 import React, { useEffect } from "react"; import { useAnimation } from "framer-motion"; import { useInView } from "react-intersection-observer"; import { Container, H1,StyledBox } from "./Styles"; const BoxVariants = { visible: { opacity: 1, x: 0, transition: { duration: 1 } }, hidden: { opacity: 0, x: 300 }, }; const Box = () => { const controls = useAnimation(); const [ref, inView] = useInView(); useEffect(() => { if (inView) { controls.start("visible"); } }, [controls, inView]); return ( <StyledBox ref={ref} animate={controls} initial="hidden" variants={BoxVariants} /> ); };

useAnimation hook ช่วยให้เราควบคุมลำดับที่แอนิเมชั่นของเราเกิดขึ้นได้ เรามีสิทธิ์เข้าถึงเมธอด controls.start และ controls.stop ที่เราสามารถใช้เพื่อเริ่มและหยุดแอนิเมชั่นของเราได้ด้วยตนเอง เราส่งแอนิเมชั่นที่ hidden เริ่มต้นไปที่ StyledBox เราส่งผ่านการควบคุมที่เรากำหนดด้วยวิธี start ไปยัง StyledBox เคลื่อนไหว prop

ตะขอ useInView ของ react-intersection-observer ช่วยให้เราติดตามเมื่อส่วนประกอบมองเห็นได้ในวิวพอร์ต useInView hook ช่วยให้เราเข้าถึง ref ซึ่งเราส่งผ่านไปยังส่วนประกอบที่เราต้องการดู และบูลีน inView ที่จะบอกเราว่าองค์ประกอบนั้นเป็น inView หรือไม่ เราใช้ useEffect เพื่อเรียก controls.start ทุกครั้งที่องค์ประกอบที่เรากำลังดูอยู่ StyledBox อยู่ในมุมมอง เราส่งผ่าน controls และ inView เป็นการพึ่งพาของ useEffect นอกจากนี้เรายังส่งต่อตัวแปรที่เรากำหนด BoxVariants ไปยัง StyledBox

แอนิเมชั่นฮีโร่

เราจะสร้างแอนิเมชั่นแบนเนอร์ฮีโร่สุดเท่โดยใช้ useCycle hook เราจะเข้าใจว่า useCycle ช่วยให้เราหมุนเวียนภาพเคลื่อนไหวได้อย่างไร

 import React, { useEffect } from "react"; import { useCycle } from "framer-motion"; import { Container, H1, HeroSection, Banner, TextBox } from "./Styles"; import { ReactComponent as BannerIllustration } from "./bighead.svg"; const H1Variants = { initial: { y: -200, opacity: 0 }, animate: { y: 0, opacity: 1, transition: { delay: 1 } }, }; const TextVariants = { initial: { x: 400 }, animate: { x: 0, transition: { duration: 0.5 } }, }; const BannerVariants = { animationOne: { x: -250, opacity: 1, transition: { duration: 0.5 } }, animationTwo: { y: [0, -20], opacity: 1, transition: { yoyo: Infinity, ease: "easeIn" }, }, };

เรากำหนด 3 ตัวแปร, H1Variants , TextVariants และ BannerVariants อย่างไรก็ตาม จุดสนใจของเราคือ BannerVariants เรากำหนด 2 แอนิเมชั่น, animationOne หนึ่งและ animationTwo สองใน BannerVariants นี่คือแอนิเมชั่นที่เราส่งผ่านไปยัง useCycle เพื่อหมุนเวียน

 const [animation, cycleAnimation] = useCycle("animationOne", "animationTwo"); useEffect(() => { setTimeout(() => { cycleAnimation(); }, 2000); }, []);

useCycle ทำงานคล้ายกับ useState hook ในอาร์เรย์ที่ทำลายล้าง animation แสดงถึงแอนิเมชั่นที่ทำงานอยู่ ไม่ว่าจะเป็น animationOne หนึ่งหรือ animationTwo สอง ฟังก์ชัน cylceAnimation ที่วนไปมาระหว่างแอนิเมชั่นที่เรากำหนด เราส่งแอนิเมชั่นที่เราต้องการหมุนเวียนเข้าสู่ useCycle และเรียก cylceAnimation หลังจาก 2 วินาทีใน useEffect

 <div className="App"> <Container> <H1 variants={H1Variants} initial="initial" animate="animate"> Cool Hero Section Anmiation </H1> <HeroSection> <TextBox variants={TextVariants} initial="initial" animate="animate"> Storage shed, troughs feed bale manure, is garden wheat oats at augers. Bulls at rose garden cucumbers mice sunflower wheat in pig. Chainsaw foal hay hook, herbs at combine harvester, children is mallet. Goat goose hen horse. Pick up truck livestock, pets and storage shed, troughs feed bale manure, is garden wheat oats at augers. Lamb. </TextBox> <Banner variants={BannerVariants} animate={animation}> <BannerIllustration /> </Banner> </HeroSection> </Container> </div>

ในตอนท้ายของทุกอย่าง เราจะส่งต่อตัวแปรต่างๆ ไปยังส่วนประกอบที่เกี่ยวข้องและเฝ้าดูความมหัศจรรย์เกิดขึ้น ด้วยวิธีนี้ Banner จะเลื่อนเข้ามาจากด้านขวาในขั้นต้นตามแอนิเมชั่นที่เรากำหนดไว้ใน animationOne หนึ่ง และหลังจากนั้น 2 วินาที ไซ cycleAnimation แอนิเมชั่นจะถูกเรียกซึ่งจะทริกเกอร์ animationTwo สอง

อย่างที่หมูผู้เฉลียวฉลาดเคยกล่าวไว้ว่า "ก็แค่นั้นแหละ"

บทสรุป

เราได้ศึกษาพื้นฐานของ Framer Motion แล้ว และได้เห็นโปรเจ็กต์ตัวอย่างบางโปรเจ็กต์ที่ให้ภาพรวมคร่าวๆ ของแอนิเมชั่นที่เราสามารถสร้างได้ อย่างไรก็ตาม คุณสามารถทำอะไรได้อีกมากมายกับมัน ฉันแนะนำให้คุณดำดิ่งลงไปในเอกสารและออกไปผจญภัย

ทรัพยากร

  • เอกสาร Framer Motion Api, Framer Motion
  • react-intersection-observer, npm
  • Framer Motion สำหรับ React, NetNinja