๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
IT/React

[react] react Framer-motion ๋ฆฌ์•กํŠธ ํ”„๋ ˆ์ด๋จธ ํ™œ์šฉํ•˜๊ธฐ (์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๊ฐ„ํŽธํ•˜๊ฒŒ!)

by ITyranno 2024. 1. 10.
728x90
๋ฐ˜์‘ํ˜•

 

 

 

 

 

 

 

 

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์„ธ๊ณ„๋ฅผ ํƒ๊ตฌํ•ฉ์‹œ๋‹ค.

 

 

 

 

 

react Framer-motion ๋ฆฌ์•กํŠธ ํ”„๋ ˆ์ด๋จธ ๋ชจ์…˜ ํ™œ์šฉํ•˜๊ธฐ

 

 

 

React Framer Motion์€ ์ฃผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค:

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ œ์–ด: ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ ์ปดํฌ๋„ŒํŠธ๋‚˜ DOM ์š”์†Œ๋ฅผ ์• ๋‹ˆ๋ฉ”์ด์…˜ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์›€์ง์ž„, ํฌ๊ธฐ ์กฐ์ ˆ, ํšŒ์ „ ๋“ฑ ๋‹ค์–‘ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ œ์Šค์ฒ˜ ์ฒ˜๋ฆฌ: ํ„ฐ์น˜, ํด๋ฆญ ๋“ฑ์˜ ์ œ์Šค์ฒ˜ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์ด์— ๋”ฐ๋ฅธ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ ๊ฐ„ ํ†ต์‹ : ๋‹ค์–‘ํ•œ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ํ†ต์‹ ์„ ์ด‰์ง„ํ•˜๋ฉฐ, ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํ†ตํ•œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ํ–ฅ์ƒ์— ๊ธฐ์—ฌํ•ฉ๋‹ˆ๋‹ค.

 

 

 

 

 

 

react Framer-motion ๋ฆฌ์•กํŠธ ํ”„๋ ˆ์ด๋จธ ๋ชจ์…˜ ๊ตฌํ˜„ ์˜ˆ์‹œ

 

 

๊ตฌํ˜„ ์˜ˆ์‹œ ํ™”๋ฉด์ž…๋‹ˆ๋‹ค.

 

๋ฐ‘์ค„ ํšจ๊ณผ, ๋งˆ์šฐ์Šค hover ์‹œ box๊ฐ€ ์ปค์ง€๋Š” ํšจ๊ณผ, ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜๋Š” ํšจ๊ณผ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

 

 

 

react Framer-motion ๋ฆฌ์•กํŠธ ํ”„๋ ˆ์ด๋จธ ๋ชจ์…˜ ํ™œ์šฉ ๋ฐฉ๋ฒ•

 

 

1. ๊ณต์‹ ์‚ฌ์ดํŠธ

 

๋‹ค์–‘ํ•œ ํšจ๊ณผ์™€ ์‚ฌ์ดํŠธ๋Š” ์•„๋ž˜ ์‚ฌ์ดํŠธ ์ฐธ๊ณ  ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

https://www.framer.com/motion/

 

Documentation | Framer for Developers

An open source, production-ready motion library for React on the web.

www.framer.com

 

 

 

1. ์ œ์Šค์ฒ˜ ์ด๋ฒคํŠธ์™€ ํŠธ๋žœ์ง€์…˜: whileHover, whileTap ๋“ฑ์˜ ์ œ์Šค์ฒ˜ ๊ด€๋ จ ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ƒํ˜ธ ์ž‘์šฉ์— ๋ฐ˜์‘ํ•˜๋ฉฐ ๋ถ€๋“œ๋Ÿฌ์šด ํŠธ๋žœ์ง€์…˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

2. ํ”„๋ ˆ์ž„-๋ณ„ ์• ๋‹ˆ๋ฉ”์ด์…˜: animate ์†์„ฑ์„ ํ†ตํ•ด ํŠน์ • ํ”„๋ ˆ์ž„์—์„œ์˜ ์†์„ฑ์„ ์ง€์ •ํ•˜๊ณ , ๋ถ€๋“œ๋Ÿฝ๊ฒŒ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

 

2. ์„ค์น˜

 

์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

npm install framer-motion

 

 

 

3. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

 

motion์„ ์ž„ํฌํŠธํ•˜๊ณ  motion.div๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

import { motion } from 'framer-motion'

<motion.div animate={{ scale: 0.7 }} />

 

 

 

4. ์ž‘์„ฑ ์ฝ”๋“œ

 

์˜ˆ์‹œ ํ™”๋ฉด์— ๋Œ€ํ•œ ์ž‘์„ฑ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

 

 

import style from './Main.module.css';
import { motion } from "framer-motion";
import { Link } from 'react-router-dom';
import { useState } from 'react';

function Main() {
    // ๋ฒ„ํŠผ ์ด๋ฏธ์ง€์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒํƒœ๋ฅผ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•œ state
    const [isHovered, setIsHovered] = useState(false);

    // ๋ฒ„ํŠผ ๋ฐ•์Šค์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒํƒœ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    const buttonBoxVariants = {
        hover: { scale: 1.1 },
        tap: { scale: 0.9 }
    };

    // ๋ฒ„ํŠผ ์ด๋ฏธ์ง€์˜ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ƒํƒœ๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    const buttonIconVariants = {
        hidden: { x: -30, opacity: 0 }, // ์™ผ์ชฝ์— ์ˆจ๊ฒจ์ง„ ์ƒํƒœ
        visible: { x: 0, opacity: 1 } // ์›๋ž˜ ์œ„์น˜์— ๋‚˜ํƒ€๋‚œ ์ƒํƒœ
    };

    return (
        <div className={style.mainpage}>
            <div className={style.main}>
                <div className={style.main_text}>
                    <h1 className={style.main_text1}><span className={style.highlight1}>๋ง›</span>์ง‘,</h1>
                    <h1 className={style.main_text2}><span className={style.highlight2}>๋“ฑ์‚ฐ</span>๋กœ,</h1>
                    <h1 className={style.main_text2}><span className={style.highlight1}>์‚ฐ์•…๊ธฐ์ƒ์ •๋ณด</span>๋ฅผ</h1>
                    <h1 className={style.main_text3}>
                        <span>ํ•œ ๋ฒˆ์˜ ๊ฒ€์ƒ‰์œผ๋กœ ํ™•์ธํ•˜์„ธ์š”.</span>
                        <motion.span
                            className={style.underline}
                            initial={{ width: 0 }}
                            animate={{ width: "100%" }}
                            transition={{
                                repeat: Infinity,
                                repeatType: "reverse",
                                duration: 3
                            }}
                        />
                    </h1>
                </div>
                <div className={style.main_box}>
                    <Link className={style.main_map} to="/map">
                        <motion.div
                            className={style.box}
                            variants={buttonBoxVariants}
                            whileHover="hover"
                            whileTap="tap"
                            onHoverStart={() => setIsHovered(true)}
                            onHoverEnd={() => setIsHovered(false)}
                        >
                            <div className={style.main_mapimg}>
                                <img src={`${process.env.PUBLIC_URL}/img/mapimg.png`} alt="mapimg" className={style.mapimg} />
                            </div>
                            {/* ํ…์ŠคํŠธ ๋ถ€๋ถ„ */}
                            <div className={style.box_text1}>
                                ๋“ฑ์‚ฐ ์ •๋ณด ๊ฒ€์ƒ‰ํ•˜๋Ÿฌ ๊ฐ€๊ธฐ
                            </div>
                            {/* ์ด๋ฏธ์ง€ ๋ถ€๋ถ„ */}
                            <motion.img
                                src={`${process.env.PUBLIC_URL}/img/button.svg`}
                                alt="๋ฒ„ํŠผ"
                                className={style.buttonIcon}
                                variants={buttonIconVariants}
                                initial="hidden"
                                animate={isHovered ? "visible" : "hidden"}
                                transition={{ duration: 0.3 }}
                            />
                        </motion.div>
                    </Link>
                </div>
            </div>
        </div>
    );
}

export default Main;

 

 

 

 

 

 

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ react์—์„œ framer-motion์„ ์‚ฌ์šฉํ•˜์—ฌ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

728x90
๋ฐ˜์‘ํ˜•

loading