2025. 8. 9. 22:25ใReact
๋ณ์ ์์ฝ ๋ฐ ์ปค๋ฎค๋์ผ์ด์ ํ๋ซํผ ํ๋ก์ ํธ์์ ๋ก๊ทธ์ธ, ํ์๊ฐ์ ์ ์ ์ธํ ๋ชจ๋ ํ์ด์ง์ ์ ์ฉ๋ ๋ค๋น๊ฒ์ด์ ๋ฐ ๊ฐ๋ฐ์ ๋ด๋นํ์ต๋๋ค.
์ด ๊ธ์์๋ ๋ค๋น๊ฒ์ด์ ๋ฐ์ ์ค๊ณ๋ถํฐ ๊ตฌํ, ๊ทธ๋ฆฌ๊ณ ๋ฌธ์ ํด๊ฒฐ ๊ณผ์ ์ ์ ๋ฆฌํ์์ต๋๋ค.
DocQProject
DocQProject has 2 repositories available. Follow their code on GitHub.
github.com
๋ค๋น๊ฒ์ด์ ๋ฐ ์ค๊ณ
๐จ UI ์ค๊ณ
- ๋ง์ฐ์ค๋ฅผ ๋ฉ๋ด ์์ ์ฌ๋ฆฌ๋ฉด ์์์ด ๋ณ๊ฒฝ๋ฉ๋๋ค.
- ์๋ธ ๋ฉ๋ด๊ฐ ๋๋กญ๋ค์ด ํํ๋ก ๋ํ๋๋๋ก ์ค๊ณํ์์ต๋๋ค.
- ๋ฉ์ธ(Home)๊ณผ ๊ฒ์ํ์ ํ์ ํญ๋ชฉ์ด ์์ผ๋ฏ๋ก ์๋ธ ๋ฉ๋ด๋ฅผ ๋น์๋๋ค.


๐ ๋ค๋น๊ฒ์ด์ ๋ฐ ์์น
- ํ์ด์ง ์๋จ์ ๊ณ ์ ๋ฉ๋๋ค.
- <header> ํ๊ทธ๋ก ์์ญ ์ ์ํ์์ต๋๋ค.
๐ก <head>์ <header> ์ฐจ์ด
head: ๋ฌธ์ ์ ๋ณด๋ฅผ ๋ด์ ๋ธ๋ผ์ฐ์ ๋ ๊ฒ์์์ง์ด ํด์ํ์ง๋ง, ์ฌ์ฉ์์๊ฒ๋ ๋ณด์ด์ง ์๋ ์์ญ
header: ์นํ์ด์ง ์๋จ์ ์ฝํ ์ธ ์์ญ (๋ก๊ณ , ๋ค๋น๊ฒ์ด์ , ์ ๋ชฉ ๋ฑ)
๐ HTML header ๊ตฌ์กฐ ๋ฐ ์์ ๊ฐ๋จ ์ค๋ช
HTML header ๊ตฌ์กฐ ๋ฐ ์์ ๊ฐ๋จ ์ค๋ช
HTML ํค๋ ๊ตฌ์กฐ์ ๋ํ ์์ธํ ์ค๋ช HTML(ํ์ดํผํ ์คํธ ๋งํฌ์ ์ธ์ด)์ ์น ํ์ด์ง์ ๋ผ๋๋ฅผ ๊ตฌ์ฑํ๋ ์ธ์ด์ ๋๋ค. ์ด ์ค HTML ๋ฌธ์์ ํค๋(Header) ๋ถ๋ถ์ ๋ฌธ์์ ๋ฉํ๋ฐ์ดํฐ(metadata)๋ฅผ ์ ์ํ๋ฉฐ, ๋ธ๋ผ
play-with.tistory.com
๋ค๋น๊ฒ์ด์ ๋ฐ ๊ธฐ์ด ๊ตฌ์ฑ
์ฃผ์ ํญ๋ชฉ
- ๋ก๊ณ
- ๋ฉ์ธ(Home)
- ๊ฒ์ํ
- ๋ณ์
- ๋ง์ดํ์ด์ง
- ๊ฒ์ ์ ๋ ฅ์ฐฝ๊ณผ ๊ฒ์ ๋ฒํผ

๋ค๋น๊ฒ์ด์ ๋ฐ ๊ตฌํ
๋ก๊ณ ๋ฃ๊ธฐ
<Link to="/">
<img
src="src/assets/Doc-Q.png"
className="w-20 h-20 me-20"
style={{ clipPath: "inset(20% 0 20% 0)" }}
alt="icon"
/>
</Link>
- ๋ก๊ณ ํด๋ฆญ ์ ๋ฉ์ธ ํ์ด์ง๋ก ์ด๋๋ฉ๋๋ค.
๋ฉ์ธ ๋ฉ๋ด ๋ง๋ค๊ธฐ
๐ก ์๋ธ ๋ฉ๋ด URL์ ์์ง ์์ด ๋ฐฐ์ด๋ก๋ง ํ์ํ์์ต๋๋ค.
NavbarMenu.jsx
function NavbarMenu({ url, menuName, subMenu = [] }) {
return (
<li>
<Link to={url}>
<span className="font-bold text-2xl px-10 py-10">{menuName}</span>
</Link>
</li>
);
}
NavigationBar.jsx
<div className="flex flex-1 flex-row h-full">
<ul className="flex flex-row h-full">
<NavbarMenu url="/" menuName="๋ฉ์ธ" />
<NavbarMenu url="/board" menuName="๊ฒ์ํ" />
<NavbarMenu
url="/mypage"
menuName="๋ง์ด ํ์ด์ง"
subMenu={["๋ด ์ ๋ณด", "๋ด ์์ฝ", "๋ด ๋ณ์"]}
/>
<NavbarMenu
url="/"
menuName="๋ณ์"
subMenu={["์น๊ณผ", "์๊ณผ", "์ด๋น์ธํ๊ณผ", "ํผ๋ถ๊ณผ"]}
/>
</ul>
</div>
๊ฒ์ ๋ง๋ค๊ธฐ
๐ก ์์ง ๋ฐฑ์๋ ์ฐ๋์ด ์ ๋์ด submit ๊ธฐ๋ฅ์ ๊ตฌํ๋์ง ์์์ต๋๋ค.
<div className="flex flex-row">
<form role="search" className="flex max-w-md px-5">
<input
type="search"
placeholder="๊ฒ์..."
aria-label="Search"
className="w-full px-3 py-2 border border-gray-300 rounded"
/>
</form>
<button className="px-4 py-2 text-white bg-black rounded">
๊ฒ์
</button>
</div>
๋ง์ฐ์ค ์ค๋ฒ ํจ๊ณผ
๐ [Javascript] ๋ง์ฐ์ค ์ด๋ฒคํธ(event) ์ข ๋ฅ
[Javascript] ๋ง์ฐ์ค ์ด๋ฒคํธ(event) ์ข ๋ฅ
๋ง์ฐ์ค ์ด๋ฒคํธ์ ์ข ๋ฅ๋ฅผ ์์๋ณด๊ณ , ๊ฐ ์ด๋ฒคํธ๋ค์ด ์ธ์ ์ด๋ป๊ฒ ๋์ํ๋์ง ์ ๋ฆฌํด ๋ณด์์ต๋๋ค. 0. ๋ง์ฐ์ค ์ด๋ฒคํธ์ ์ข ๋ฅ 1. click, mousedown, mouseup 2. dblclick 3. mousemove 4. mouseover, mouseout 5. mouseenter, mous
hianna.tistory.com
onMouseEnter์ onMouseLeave๋ฅผ ํตํด ๋ง์ฐ์ค ์ค๋ฒ ์ ์์ ๋ณ๊ฒฝ๋๋๋ก ํ์์ต๋๋ค.

function NavbarMenu({ url, menuName, isSubMenu = false}) {
const [isActiveSection, setIsActiveSection] = useState(false);
return (
<li
onMouseEnter={() => setIsActiveSection(true)}
onMouseLeave={() => setIsActiveSection(false)}
>
<Link to={url}>
<span
className={`font-bold text-2xl px-10 py-10 transition-colors ${isActiveSection ? "text-blue-600 border-b-4 border-blue-600 pb-4" : ""}`}
>
{menuName}
</span>
</Link>
</li>
);
}
โ ๏ธ ๊น๋นก๊ฑฐ๋ฆผ ๋ฌธ์

- border-b-4์ pb-4๊ฐ ํจ๊ป ์ ์ฉ๋์ด ๋์ด๊ฐ ๋ณํด ๋ง์ฐ์ค ๊ฒฝ๊ณ๋ฉด์์ ๊น๋นก๊ฑฐ๋ฆผ ๋ฐ์ํ์์ต๋๋ค.
- pb-4 ์ ๊ฑฐ + border-transparent ์ฌ์ฉ โก๏ธ ๋์ด ๋ณํ ์์ด ์์๋ง ๋ณ๊ฒฝ
์์ ์ฝ๋
<Link to={url} className="">
<span
className={`
font-bold text-2xl px-10 py-3 border-b-4 transition-colors
${isActiveSection ? "text-blue-600 border-blue-600" : "border-transparent"}
`}
>
{menuName}
</span>
</Link>
ํ์ ๋ฉ๋ด(์๋ธ ๋ฉ๋ด) ๋๋กญ๋ค์ด
- ๋ถ๋ชจ ๋ฉ๋ด: relative
- ์๋ธ ๋ฉ๋ด: absolute
- ๋ง์ฐ์ค ์ค๋ฒ ์ ํ์ ๋ฉ๋ด๋ฅผ ํ์ํฉ๋๋ค.

function NavbarMenu({ url, menuName, subMenu = [] }) {
const [isActiveSection, setIsActiveSection] = useState(false);
const isSubMenuActive = isActiveSection && subMenu.length !== 0;
return (
<li
className={`flex items-center h-full ${isSubMenuActive ? "relative" : ""}`}
onMouseEnter={() => setIsActiveSection(true)}
onMouseLeave={() => setIsActiveSection(false)}
>
<Link to={url}>
<span
className={`font-bold text-2xl px-10 py-3 border-b-4 transition-colors ${
isActiveSection ? "text-blue-600 border-blue-600" : "border-transparent"
}`}
>
{menuName}
</span>
</Link>
{isSubMenuActive && (
<ul className="absolute top-full left-0 flex flex-col justify-center items-center bg-white shadow w-full">
{subMenu.map((item, index) => (
<li key={index} className="font-bold my-5 mx-3">
{item}
</li>
))}
</ul>
)}
</li>
);
}
๋ณด์์ ๋ฐ ํฅํ ๊ณํ
์ด๋ฒ ๊ตฌํ์์๋ ๋ค๋น๊ฒ์ด์
๋ฐ์ ์ ๋ฐ์ ์ธ ๊ตฌ์กฐ ์ค๊ณ โก๏ธ ์๋งจํฑ ํ๊ทธ ์ ์ฉ โก๏ธ hover๊น์ง ๊ตฌํ ์๋ฃํ์ต๋๋ค.
๋ค๋ง ์๋ธ ๋ฉ๋ด ํญ๋ชฉ์ ํ์ฌ ํ์ด์ง ์ด๋ ๋ถ๊ฐ, ๊ฒ์ ๊ธฐ๋ฅ๋ UI๋ง ๊ตฌํ๋ ์ํ์
๋๋ค.
์์ผ๋ก ๊ฐ์ ํ ์
- ๋ฐฑ์๋ ์ฐ๋
- ์๋ฒ์์ ์๋ธ ๋ฉ๋ด ๋ฐ์ดํฐ ๋์ ๋ ๋๋ง
- ์๋ธ ๋ฉ๋ด ํด๋ฆญ ์ ํด๋น ํ์ด์ง๋ก ์ด๋ ๊ฐ๋ฅํ๋๋ก ๋ผ์ฐํ ์ค์
- ๊ฒ์ ๊ธฐ๋ฅ
- ๊ฒ์์ด ์ ๋ ฅ ํ ๋ฒํผ ํด๋ฆญ ๋๋ Enter ์ /search ํ์ด์ง๋ก ์ด๋
- ์๋ฒ์์ ๊ฒ์ ๊ฒฐ๊ณผ ๋ฐ์ ๋ณ์ ๋ฆฌ์คํธ ์ถ๋ ฅ