這篇文章將指導您如何在 React 應用中創建一個可收合的導航欄。該導航欄在縮合時僅顯示圖標,展開時顯示完整的圖標和標題,提升使用者體驗。
我們的目標是實現以下功能:
首先,確保您的專案具有以下結構,以便於組件的管理:
src
│
├── components
│ ├── Header
│ │ ├── Header.jsx
│ │ └── header.module.css
│ ├── NavBar
│ │ ├── NavBar.jsx
│ │ └── navbar.module.css
└── assets
└── travel.png
在這個組件中,我們會使用 useState 來管理導航欄的縮合狀態,並透過滑鼠事件來切換狀態。有關useState後續的單元會詳細說明.
import { useState } from "react";
import styles from "./header.module.css";
import Logo from "../../assets/travel.png"; // 引入 Logo 圖片
import { Divider } from "antd"; // 引入 Ant Design 的 Divider
import NavBar from "../NavBar"; // 引入 NavBar 組件
export default function Header() {
const [isShrink, setIsShrink] = useState(true); // 設定初始狀態為縮合
return (
<div
className={`${styles.headerContainer} ${isShrink ? styles.shrink : styles.expand}`}
onMouseEnter={() => setIsShrink(false)} // 滑鼠進入時展開
onMouseLeave={() => setIsShrink(true)} // 滑鼠離開時縮合
>
<div className={styles.logoBox}>
<img src={Logo} alt="logo" className={styles.logo} />
{!isShrink && <h1 className={styles.title}>Travel</h1>} {/* 當未縮合時顯示標題 */}
{!isShrink && <Divider className={styles.divider} />} {/* 當未縮合時顯示分隔線 */}
</div>
<NavBar isShrink={isShrink} /> {/* 傳遞狀態給 NavBar */}
</div>
);
}
.headerContainer {
display: flex; /* 使用 Flexbox 排版 */
flex-direction: column; /* 垂直排列 */
align-items: center; /* 水平置中 */
height: 100vh; /* 高度佔滿整個視窗 */
padding: 1rem 0; /* 上下內邊距 */
background-color: #282c34; /* 背景顏色 */
transition: all 0.3s ease; /* 讓所有屬性都有平滑過渡效果 */
width: 60px; /* 初始寬度 */
}
.expand {
width: 200px; /* 展開時的寬度 */
}
.shrink {
width: 60px; /* 縮合時的寬度 */
}
.logoBox {
display: flex; /* 使用 Flexbox 排版 */
flex-direction: column; /* 垂直排列 */
align-items: center; /* 水平置中 */
justify-content: center; /* 垂直置中 */
margin-bottom: 1rem; /* 下邊距 */
transition: all 0.3s ease; /* 讓所有屬性都有平滑過渡效果 */
}
.logo {
width: 40px; /* 縮合時的 Logo 大小 */
transition: width 0.3s ease; /* Logo 寬度過渡效果 */
}
.title {
font-size: 16px; /* 縮合時的標題大小 */
}
.expand .logo {
width: 80px; /* 展開時的 Logo 大小 */
}
.expand .title {
font-size: 24px; /* 展開時的標題大小 */
}
.divider {
border-color: #ffffff; /* 分隔線顏色 */
opacity: 0; /* 縮合時隱藏分隔線 */
transition: opacity 0.3s ease; /* 分隔線顯示過渡效果 */
}
.expand .divider {
opacity: 1; /* 展開時顯示分隔線 */
}
在這個組件中,根據 isShrink 狀態來顯示或隱藏導航項目的標題。
import styles from "./navbar.module.css";
const NavBar = ({ isShrink }) => {
return (
<div className={styles.navContainer}>
<div className={styles.navbox}>
<div className={styles.icon}>🏠</div>
{!isShrink && <div className={styles.title}>Home</div>} {/* 當未縮合時顯示標題 */}
</div>
<div className={styles.navbox}>
<div className={styles.icon}>📍</div>
{!isShrink && <div className={styles.title}>Destinations</div>} {/* 當未縮合時顯示標題 */}
</div>
{/* 添加其他導航項目 */}
</div>
);
};
export default NavBar;
.navContainer {
display: flex; /* 使用 Flexbox 排版 */
flex-direction: column; /* 垂直排列 */
align-items: center; /* 水平置中 */
width: 60px; /* 初始寬度 */
overflow: hidden; /* 隱藏溢出的內容 */
transition: width 0.3s ease; /* 寬度過渡效果 */
}
.navContainer:hover {
width: 200px; /* 滑鼠懸停時展開的寬度 */
}
.navbox {
display: flex; /* 使用 Flexbox 排版 */
align-items: center; /* 垂直置中 */
justify-content: center; /* 水平置中 */
width: 100%; /* 佔滿整個寬度 */
padding: 0.5rem 1rem; /* 內邊距 */
border-radius: 8px; /* 邊角圓弧 */
transition: background-color 0.3s ease; /* 背景顏色過渡效果 */
margin: 0.5rem 0; /* 上下邊距 */
}
.navbox:hover {
background-color: rgba(188, 196, 249, 0.5); /* 懸停時背景顏色 */
}
/* Icon 的樣式 */
.icon {
display: flex;
justify-content: center; /* 水平置中 */
align-items: center; /* 垂直置中 */
width: 100%; /* 確保寬度填滿 */
}
/* Title 的樣式 */
.title {
font-size: larger; /* 標題字型大小 */
color: aliceblue; /* 標題顏色 */
white-space: nowrap; /* 不換行 */
}
.navbox .title {
display: none; /* 縮合時隱藏標題 */
}
.navContainer:hover .navbox .title {
display: inline-block; /* 懸停時顯示標題 */
}
將所有組件整合,並啟動應用程序來測試縮合和展開的功能是否正常運作。
npm run dev