2024-08-21
【Next.js專案】購物網站建構_Layout

原文發表於 Medium。

Next.js 的 layout 就像是一間房子的基本格局。
想像你在蓋房子:
- 主要結構:layout 就是房子的主要結構 — 牆壁、屋頂和地板。這些是每個房間都會用到的基本元素。
- 共用空間:像是客廳或走廊,代表網站上面共用的部分,如導航欄或頁尾。
- 個別房間:則代表網站的不同頁面,可以有不同的擺設和用途。
- 整體感:雖然每個房間可能風格不同,但整棟房子給人的感覺是協調的。
Layout可以讓設計程式碼更加簡潔,也維持了網站的整體感受,對於對於建立網站品牌是很有幫助的。
我們開始建立Layout吧。
在我們的購物網站中,我希望能夠有一個Header來放置網站的Logo、導航列,有一個Footer來放置版權資訊。在使用create-next-app建立起來的專案中已經內建了一個layout.js在app資料夾內:
import { Inter } from 'next/font/google'
import './globals.css'
const inter = Inter({ subsets: ['latin'] })
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({
children,
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
)
}
在這裡面的inter常數只是用來引入google字型的,可以忽略。而這個檔案匯出的Metadata跟HTML的意思差不多,就是設定瀏覽器標籤頁的title屬性以及搜尋引擎顯示用的description。重點在RootLayout函數。
RootLayout函數
這個函數是個Wrapper,不是漢堡王華堡,但意思差不多,就是把內容物上下都包起來的罩子,在這個主要的Wrapper裡有html跟body標籤,然後所有在app下方的主page或子資料夾內的page內容都會被放在children的位置。
因此我們可以把需要貫穿各頁面的元件都放在layout上:
export default function RootLayout({
children,
}) {
return (
<html lang="en">
<body className={inter.className}>
<Navbar />
<main>
{children}
</main>
<Footer />
</body>
</html>
)
}
上方使用next.js官網上的案例,示範在頁面上方加導航列跟頁腳的寫法。
除了是頁面佈局外,layout還可以作為Fetch資料的地方,例如從資料庫下載商品或客戶資料,可以這樣:
export default function RootLayout({
children,
}) {
const { data, error } = useSWR('/api/navigation', fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return (
<html lang="en">
<body className={inter.className}>
<Navbar />
<main>
{children}
</main>
<Footer />
</body>
</html>
)
}
只是我這次沒有需要用到SWR。在本次專案DEMO中我暫時只需要下面這樣的layout:
import { Inter } from "next/font/google";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata = {
title: "Billy衣飾",
description: "使用Next.js創建的簡單購物網站",
};
export default function RootLayout({ children }) {
return (
<html lang="zh-TW">
<body className={inter.className}>
<div className="flex flex-col min-h-screen">
<Header />
<main className="flex-grow container mx-auto px-4 py-8">
{children}
</main>
<Footer />
</div>
</body>
</html>
);
}
為了讓Header跟Footer各自緊貼上下方,因此我在所有元素外加了一層Div,並使用TailwindCSS中的flex跟flex-col屬性將內容物彼此排列靠邊,然後將main設定為flex-grow : 1,讓main取得所有的空白間格。
Header:
"use client";
import Link from "next/link";
// import { useContext } from "react";
// import { CartContext } from "@/context/CartContext";
export default function Header() {
// const { cart } = useContext(CartContext);
return (
<header className=" bg-cyan-700 text-white p-4">
<div className="container mx-auto flex justify-between items-center">
<Link
href="/"
className="text-2xl font-bold"
>
<span className=" font-extralight text-4xl mx-1 text-teal-200">
BILLY
</span>
衣飾
</Link>
<nav>
<ul className="flex space-x-4">
<li>
<Link href="/">首頁</Link>
</li>
<li>
<Link href="/cart">
購物車 (0)
{/*購物車 ({cart.length})*/}
</Link>
</li>
</ul>
</nav>
</div>
</header>
);
}
在 Header中打算使用context 來索取購物車的內容,用來實現顯示購物車內容物數量的功能。而context怎麼寫,後續會說,稍安勿躁,我們暫時只用“0”佔個位置。
Footer:
export default function Footer() {
return (
<footer className=" bg-sky-100 p-4 mt-8">
<div className="container mx-auto text-center">
<p>
© 2024
BillyHsu購物網站。保留所有權利。
</p>
</div>
</footer>
);
}
頁腳就非常簡單,一般來說還可以加入聯絡方式等資訊。
看看成果吧
Header
Footer
很好的開始!我們接下來的文章順著來講資料的問題,也就是context怎麼寫,怎麼用,讓我們的購物車物品數量能夠在header中呈現出來吧!
若喜歡這樣的文章,還請給我幾個掌聲,您的支持是我寫下去的原動力!