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

[react] ์Šคํฌ๋กค์— ๋”ฐ๋ผ ๋‚˜ํƒ€๋‚˜๊ณ  ์‚ฌ๋ผ์ง€๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๊ตฌํ˜„ํ•˜๊ธฐ (Navbar)

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

 

 

 

 

 

 

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

 

 

 

 

 

 

์Šคํฌ๋กค์— ๋”ฐ๋ผ ๋‚˜ํƒ€๋‚˜๊ณ  ์‚ฌ๋ผ์ง€๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ๊ตฌํ˜„ํ•˜๊ธฐ

 

 

 

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์Šคํฌ๋กค์— ๋”ฐ๋ผ ๋‚˜ํƒ€๋‚˜๊ณ  ์‚ฌ๋ผ์ง€๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

์Šคํฌ๋กค์„ ๋‚ด๋ฆด ๋•Œ๋Š” ์‚ฌ๋ผ์กŒ๋‹ค๊ฐ€, ์Šคํฌ๋กค์„ ์˜ฌ๋ฆฌ๋ฉด ๋‹ค์‹œ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

 

 

 

 

๊ตฌํ˜„ ํ™”๋ฉด

 

 

 

 

 

 

 

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

 

๋งˆ์ง€๋ง‰ ์Šคํฌ๋กค ์œ„์น˜๋ฅผ ๊ธฐ์–ตํ•˜์—ฌ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”์˜ ํ‘œ์‹œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

์Šคํฌ๋กค์ด ์•„๋ž˜๋กœ ์ง„ํ–‰ ์ค‘์ด๋ฉด false, ์Šคํฌ๋กค์ด ์œ„๋กœ ์ง„ํ–‰ ์ค‘์ด๋ฉด true๋กœ ์„ค์ •ํ•˜์—ฌ ๋ฐ” ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

 

Nav.jsx

import { useEffect, useState } from 'react';
import style from './Nav.module.css'
import { Link } from 'react-router-dom';

function Nav() {
    // ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ํ‘œ์‹œ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” state
    const [showNav, setShowNav] = useState(true);
    // ๋งˆ์ง€๋ง‰ ์Šคํฌ๋กค ์œ„์น˜๋ฅผ ์ €์žฅํ•˜๋Š” state
    const [lastScrollY, setLastScrollY] = useState(0);

    useEffect(() => {
        // ์Šคํฌ๋กค ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜
        const handleScroll = () => {
            const currentScrollY = window.scrollY;
            // ์Šคํฌ๋กค์ด ์•„๋ž˜๋กœ ์ง„ํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
            if (currentScrollY > lastScrollY) {
                setShowNav(false); // ์Šคํฌ๋กค์„ ๋‚ด๋ฆด ๋•Œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ์ˆจ๊ธฐ๊ธฐ
            } else {
                setShowNav(true); // ์Šคํฌ๋กค์„ ์˜ฌ๋ฆด ๋•Œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ” ํ‘œ์‹œ
            }
            // ๋งˆ์ง€๋ง‰ ์Šคํฌ๋กค ์œ„์น˜ ์—…๋ฐ์ดํŠธ
            setLastScrollY(currentScrollY);
        };

        // ์Šคํฌ๋กค ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋ก
        window.addEventListener('scroll', handleScroll);

        // ํด๋ฆฐ์—… ํ•จ์ˆ˜์—์„œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ
        return () => window.removeEventListener('scroll', handleScroll);
    }, [lastScrollY]); // lastScrollY๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค useEffect๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

    return (
        <div className={`${style.header} ${showNav ? '' : style.hideNav}`}>
            <Link className={style.Logo} to="/">
                <img src={`${process.env.PUBLIC_URL}/img/logo.svg`} alt="MDS Logo" className={style.logo} />
            </Link>
            <div className={style.navbar}>
                <Link className={style.navbarMenu} to={'/map'}>
                    <img src={`${process.env.PUBLIC_URL}/img/mountainpath.svg`} alt="๋“ฑ์‚ฐ ์ •๋ณด ์•„์ด์ฝ˜" className={style.icon1} />๋“ฑ์‚ฐ ์ •๋ณด
                </Link>
                <Link className={style.navbarMenu} to={'/review'}>
                    <img src={`${process.env.PUBLIC_URL}/img/flag.svg`} alt="๋“ฑ์‚ฐ ํ›„๊ธฐ ์•„์ด์ฝ˜" className={style.icon2} />๋“ฑ์‚ฐ ํ›„๊ธฐ
                </Link>
                <Link className={style.navbarMenu} to={'/rec'}>
                    <img src={`${process.env.PUBLIC_URL}/img/mountainrec.svg`} alt="๋“ฑ์‚ฐ๋กœ ์ถ”์ฒœ ์•„์ด์ฝ˜" className={style.icon1} />๋“ฑ์‚ฐ๋กœ ์ถ”์ฒœ๋ฐ›๊ธฐ
                </Link>
            </div>
        </div>
    )
}


export default Nav;

 

 

 

Nav.module.css

 

.hidenav ์Šคํƒ€์ผ์—์„œ navbar๋ฅผ ์ˆจ๊ธฐ๋Š” ํšจ๊ณผ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

.header {
    display: flex;
    align-items: center;
    background-color: rgba(179, 179, 179, 0.42);
    padding-left: 2rem;
    z-index: 1000;
    /* ๋‹ค๋ฅธ ์š”์†Œ๋“ค ์œ„์— ์˜ค๋„๋ก z-index ์„ค์ • */
    position: fixed;
    transition: transform 0.3s ease;
    /* transform ์†์„ฑ์— ๋Œ€ํ•œ ์ „ํ™˜ ํšจ๊ณผ */
}

.logo {
    width: 12rem;
    height: 5rem;
}

.icon1 {
    width: 3rem;
    height: 1.5rem;
}

.icon2 {
    width: 2rem;
    height: 1.1rem;
}

.navbar {
    justify-content: center;
    width: 100vw;
    text-align: center;
    font-size: 1.2rem;
}

.navbarMenu {
    margin: 5rem;
    text-decoration: none;
    color: rgb(0, 0, 0);
    transition: color 0.3s ease;
    /* ์ƒ‰์ƒ ๋ณ€ํ™”์— ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค */
    position: relative;
    /* ๊ฐ€์ƒ ์š”์†Œ์˜ ๊ธฐ์ค€์  ์„ค์ • */
    overflow: hidden;
    /* ๋ฐ‘์ค„์ด ๋งํฌ ์˜์—ญ ๋ฐ”๊นฅ์œผ๋กœ ๋‚˜๊ฐ€์ง€ ์•Š๋„๋ก ์„ค์ • */
}

.navbarMenu:hover {
    color: #3ca50f;
    /* ๋งˆ์šฐ์Šค ์˜ค๋ฒ„ ์‹œ ๊ธ€์ž ์ƒ‰์ƒ์„ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค */
}

.navbarMenu::after {
    content: '';
    /* ๊ฐ€์ƒ ์š”์†Œ์˜ ๋‚ด์šฉ์€ ๋น„์›Œ๋‘ก๋‹ˆ๋‹ค */
    position: absolute;
    left: 0%;
    /* ์™ผ์ชฝ์—์„œ 50%์˜ ์œ„์น˜์—์„œ ์‹œ์ž‘ */
    bottom: -0.5rem;
    /* ๋งํฌ ๋ฐ”๋‹ฅ์œผ๋กœ๋ถ€ํ„ฐ -0.5rem ์œ„์— ์œ„์น˜ */
    width: 0;
    /* ์ดˆ๊ธฐ ๋„ˆ๋น„๋Š” 0์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ๋ณด์ด์ง€ ์•Š๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค */
    height: 0.13rem;
    /* ๋ฐ‘์ค„์˜ ๋‘๊ป˜ */
    background: rgba(0, 0, 0, 0.279);
    /* ๋ฐ‘์ค„์˜ ์ƒ‰์ƒ */
    transition: width 0.5s ease, left 0.5s ease;
    /* ๋„ˆ๋น„์™€ ์œ„์น˜์— ๋Œ€ํ•œ ์ „ํ™˜ ํšจ๊ณผ ์„ค์ • */
}

.navbarMenu:hover::after,
.navbarMenu:focus::after {
    width: 100%;
    /* ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ฆฌ๊ฑฐ๋‚˜ ํฌ์ปค์Šค ์‹œ ๋ฐ‘์ค„์˜ ๋„ˆ๋น„๋ฅผ 100%๋กœ ๋ณ€๊ฒฝ */
    left: 0;
    /* ์œ„์น˜๋ฅผ ์™ผ์ชฝ ๋์œผ๋กœ ๋ณ€๊ฒฝ */
}

/* Nav.module.css */
.hideNav {
    transform: translateY(-100%);
    /* ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ์œ„๋กœ ์ˆจ๊น๋‹ˆ๋‹ค */
    transition: transform 0.3s ease;
    /* ๋ถ€๋“œ๋Ÿฌ์šด ์ „ํ™˜ ํšจ๊ณผ */
}

 

 

 

 

์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์Šคํฌ๋กค์— ๋”ฐ๋ผ ์‚ฌ๋ผ์ง€๊ณ  ๋‚˜ํƒ€๋‚˜๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

728x90
๋ฐ˜์‘ํ˜•

loading