إدخال حركة المبروز
نشرت: 2022-03-10في هذه المقالة ، سوف نلقي نظرة فاحصة على كيف يساعدنا Framer Motion في إنشاء رسوم متحركة رائعة. سنتعلم كيف تعمل مكونات الحركة ونتعلم كيفية ربط الرسوم المتحركة معًا. سننظر في كيفية إنشاء رسوم متحركة يتم تشغيلها بالإيماءات وتوقيتها وتمريرها باستخدام حركة Framer. على طول الطريق ، سنستخدم الأشياء التي نتعلمها لبناء خمسة تطبيقات تجريبية أعددتها لتظهر لنا كيف يمكننا دمج Framer Motion في تطبيقات العالم الحقيقي.
سيكون هذا البرنامج التعليمي مفيدًا للقراء المهتمين بدمج الرسوم المتحركة في تطبيق React الخاص بهم.
ملاحظة: تتطلب هذه المقالة فهمًا أساسيًا لكل من React و CSS.
ما هي حركة فرامير؟
Framer Motion هي مكتبة رسوم متحركة تجعل إنشاء الرسوم المتحركة أمرًا سهلاً. تساعدنا واجهة برمجة التطبيقات المبسطة في تجريد التعقيدات الكامنة وراء الرسوم المتحركة وتسمح لنا بإنشاء رسوم متحركة بسهولة.
مكونات الحركة
هذه هي اللبنات الأساسية لحركة Framer. يتم إنشاء مكونات الحركة عن طريق إضافة motion
إلى عنصر HTML و SVG العادي (على سبيل المثال ، motion.h1
). يمكن أن تقبل مكونات الحركة عدة دعائم ، على أن يكون العنصر الأساسي هو الدعامة animate
. تأخذ هذه الخاصية كائنًا حيث نحدد خصائص هذا المكون الذي نريد تحريكه. سيتم تحريك الخصائص التي نحددها عندما يتم تحميل المكون في DOM.
لنحرك نص h1 باستخدام 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
بمقدار 20 بكسل إلى اليمين والتحرك بمقدار 20 بكسل لأعلى عند التحميل. عند عدم إضافة الوحدات ، تتم العمليات الحسابية باستخدام وحدات البكسل. ومع ذلك ، يمكنك بشكل صريح تعيين الوحدات التي تريد أن تستند الحسابات إليها ، 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 تمكننا من استخراج تعريفات الرسوم المتحركة الخاصة بنا في كائن المتغيرات. لا تجعل 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" } }
بدلاً من تمرير تعريفات الرسوم animate
إلى الدعائم initial
والحركية للمكون مباشرةً ، نقوم باستخراج هذه التعريفات في كائنات مختلفة قائمة بذاتها. في الكائنات المتغيرة ، نحدد أسماء المتغيرات التي تصف اسم كل حركة على أنها متغيرات.
<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
الخاصة ، نقوم بتمرير اسم الكائنات المتغيرة لكل مكون حركة ثم نمرر في الرسوم animate
إلى الدعائم initial
والمتحركة.
يمكننا أن نأخذ إعدادنا الحالي مع المتغيرات إلى أبعد من ذلك لتقليل التكرار. باستخدام المتغيرات ، يمكننا نشر سمات الرسوم المتحركة لأسفل عبر DOM من مكون الحركة الأصل. لكي يعمل هذا ، نقوم بإنشاء متغيرات 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
.
عناصر
-
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> ); };
هنا ، نقوم باستيراد SVGs ومكون Container
ومكون Card
.
على غرار H1
و H2
في App.js
، نحدد الرسوم animate
Container
باستخدام الدعائم initial
والمتحركة. عند تحميله ، سيخلق تأثيرًا رائعًا للانزلاق من يسار المتصفح.
الآن ، 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 ودفعناها لأعلى بمقدار 50 بكسل. بعد ذلك ، في onHover
، نعيد التعتيم إلى 1 ، ونعيده إلى موضعه الافتراضي ، ونغير نوع الانتقال إلى tween
. ثم نمرر المتغيرات إلى مكونات الحركة الخاصة بكل منها. نحن نستفيد من التكاثر ، لذلك لا نحتاج إلى تعيين الخاصيات initial
IconBox
animate
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. نقوم بتبديل الموضع العلوي لـ Nav
بناءً على حالة isOpen
.
باستخدام المتغيرات ، يمكننا إنشاء علاقات توقيت بين مكونات حركة الوالدين والأطفال. نحدد العلاقة بين الأصل 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
s بشكل مشروط بناءً على حالة 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. نعرض الصيغة showModal
Modal
نحدد الرسوم animate
لـ ModalBox
و ModalContent
من خلال الدعائم initial
والمتحركة. هناك أيضًا دعامة جديدة هنا ، exit
. يتيح لنا وجود AnimatePresence
إضافة رسوم متحركة للخروج إلى ModalBox
في خاصية exit
.
تمرير الرسوم المتحركة
سنستخدم مزيجًا من خطاف useAnimation
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
بالتحكم في التسلسل الذي تحدث فيه رسومنا المتحركة. لدينا حق الوصول إلى طرق controls.start
and controls.stop
التي يمكننا استخدامها لبدء تشغيل الرسوم المتحركة وإيقافها يدويًا. نمرر الرسوم المتحركة hidden
الأولية إلى StyledBox
. قمنا بتمرير عناصر التحكم التي حددناها باستخدام طريقة start
إلى StyledBox
المتحركة.
يسمح لنا خطاف useInView
react-intersection-observer
بتتبع متى يكون أحد المكونات مرئيًا في منفذ العرض. يتيح لنا الخطاف useInView
الوصول إلى ref
، والذي نمرره إلى المكون الذي نريد مشاهدته ، و inView
المنطقي الذي يخبرنا ما إذا كان هذا العنصر inView
أم لا. نستخدم useEffect
لاستدعاء controls.start
التحكم.ابدأ متى كان العنصر الذي نشاهده ، يكون StyledBox
. نمرر في controls
و inView
useEffect
. أيضًا ، قمنا بتمرير المتغيرات التي حددناها ، BoxVariants
إلى StyledBox
.
الرسوم المتحركة البطل
سنقوم ببناء رسوم متحركة رائعة لشعار البطل باستخدام خطاف useCycle
. سوف نفهم كيف تسمح لنا 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
. في المصفوفة المدمرة ، تمثل animation
المتحركة الحركة النشطة ، سواء كانت حركة واحدة أو رسوم animationOne
animationTwo
. وظيفة cylceAnimation
التي تتنقل بين الرسوم المتحركة التي حددناها. نمرر الرسوم المتحركة التي نريد التنقل خلالها إلى useCycle
واستدعاء cylceAnimation
بعد ثانيتين من 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
، وبعد ثانيتين ، سيتم استدعاء cycleAnimation
الذي سيؤدي إلى تشغيل animationTwo
.
كما قال خنزير حكيم ذات مرة ، "هذا كل شيء يا رفاق."
خاتمة
لقد راجعنا أساسيات Framer Motion وشاهدنا بعض المشاريع التجريبية التي تعطينا لمحة عن مجموعة الرسوم المتحركة التي يمكننا إنشاؤها. ومع ذلك ، يمكنك فعل الكثير معها. أنا أشجعك على الغوص في المستندات والانطلاق.
موارد
- Framer Motion Api Docs ، Framer Motion
- رد فعل تقاطع مراقب ، نانومتر
- حركة المبروز للتفاعل ، NetNinja