回到部落格

2024-08-21

【Next.js專案】購物網站建構_Layout

【Next.js專案】購物網站建構_Layout

原文發表於 Medium

Next.js 的 layout 就像是一間房子的基本格局。

想像你在蓋房子:

  1. 主要結構:layout 就是房子的主要結構 — 牆壁、屋頂和地板。這些是每個房間都會用到的基本元素。
  2. 共用空間:像是客廳或走廊,代表網站上面共用的部分,如導航欄或頁尾。
  3. 個別房間:則代表網站的不同頁面,可以有不同的擺設和用途。
  4. 整體感:雖然每個房間可能風格不同,但整棟房子給人的感覺是協調的。

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>  
          &copy; 2024  
          BillyHsu購物網站。保留所有權利。  
        </p>  
      </div>  
    </footer>  
  );  
}

頁腳就非常簡單,一般來說還可以加入聯絡方式等資訊。

看看成果吧

HeaderFooter

很好的開始!我們接下來的文章順著來講資料的問題,也就是context怎麼寫,怎麼用,讓我們的購物車物品數量能夠在header中呈現出來吧!

若喜歡這樣的文章,還請給我幾個掌聲,您的支持是我寫下去的原動力!