Skip to content

Next.js 组件与布局

在 React 和 Next.js 中,组件是构建用户界面的核心。通过将 UI 拆分为独立、可重用的部分,我们可以更高效地开发和维护复杂的应用程序。本章将探讨如何在 Next.js 中组织组件,并创建适用于多个页面的共享布局。

1. 组件基础

在 Next.js 中,组件的编写方式与在标准 React 项目中完全相同。通常,我们会将所有组件存放在项目根目录下的 components 文件夹中,以便于管理。

创建一个简单的组件

让我们创建一个简单的 Button 组件。

  1. 创建文件components/Button.js

  2. 编写组件代码

    jsx
    // components/Button.js
    import styles from './Button.module.css';
    
    export default function Button({ children, onClick }) {
      return (
        <button className={styles.button} onClick={onClick}>
          {children}
        </button>
      );
    }
  3. 为组件添加样式 (可选):components/Button.module.css

    css
    .button {
      background-color: #0070f3;
      color: white;
      padding: 10px 20px;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      font-size: 1rem;
    }
    
    .button:hover {
      background-color: #005bb5;
    }

在页面中使用组件

现在,你可以在任何页面中导入并使用这个 Button 组件。

jsx
// pages/index.js
import Button from '../components/Button';

export default function HomePage() {
  const handleClick = () => {
    alert('Button clicked!');
  };

  return (
    <div>
      <h1>Welcome to My App</h1>
      <Button onClick={handleClick}>Click Me</Button>
    </div>
  );
}

2. 页面布局 (Layouts)

在大多数网站中,多个页面会共享相同的结构,例如页眉 (Header)、页脚 (Footer) 和导航栏 (Navigation Bar)。在 Next.js 中,有几种方法可以实现这种共享布局。

方法 1:创建布局组件

最常见的方法是创建一个 Layout 组件,然后用它来包裹每个页面的内容。

  1. 创建 Layout 组件components/Layout.js

    这个组件通常包含页眉、页脚,并通过 children prop 来渲染页面内容。

    jsx
    // components/Layout.js
    import Head from 'next/head';
    import Header from './Header';
    import Footer from './Footer';
    
    export default function Layout({ children, title = 'My Next.js App' }) {
      return (
        <div>
          <Head>
            <title>{title}</title>
            <meta charSet="utf-8" />
            <meta name="viewport" content="initial-scale=1.0, width=device-width" />
          </Head>
    
          <Header />
    
          <main>{children}</main>
    
          <Footer />
        </div>
      );
    }

    我们还需要创建 HeaderFooter 组件。

    components/Header.js

    jsx
    import Link from 'next/link';
    import styles from './Header.module.css';
    
    export default function Header() {
      return (
        <header className={styles.header}>
          <nav>
            <Link href="/">Home</Link>
            <Link href="/about">About</Link>
            <Link href="/contact">Contact</Link>
          </nav>
        </header>
      );
    }

    components/Footer.js

    jsx
    import styles from './Footer.module.css';
    
    export default function Footer() {
      return (
        <footer className={styles.footer}>
          <p>© {new Date().getFullYear()} My Awesome App. All rights reserved.</p>
        </footer>
      );
    }
  2. _app.js 中使用 Layout 组件

    为了让所有页面都使用这个布局,我们可以在 pages/_app.js 中包裹 Component

    jsx
    // pages/_app.js
    import Layout from '../components/Layout';
    import '../styles/globals.css';
    
    function MyApp({ Component, pageProps }) {
      return (
        <Layout>
          <Component {...pageProps} />
        </Layout>
      );
    }
    
    export default MyApp;

    通过这种方式,Layout 组件会自动应用于所有页面,而无需在每个页面文件中单独导入。

方法 2:每页布局 (Per-Page Layouts)

有时,你的应用中可能需要多种不同的布局(例如,一种用于主应用,一种用于管理后台)。在这种情况下,你可以为页面组件添加一个 getLayout 属性。

  1. 修改 _app.js

    首先,修改 _app.js 以支持 getLayout 函数。

    jsx
    // pages/_app.js
    import '../styles/globals.css';
    
    export default function MyApp({ Component, pageProps }) {
      // 如果页面有 getLayout 方法,则使用它
      const getLayout = Component.getLayout || ((page) => page);
    
      return getLayout(<Component {...pageProps} />);
    }
  2. 在页面中指定布局

    现在,你可以在需要特定布局的页面中定义 getLayout

    jsx
    // pages/dashboard.js
    import AdminLayout from '../components/AdminLayout';
    
    export default function DashboardPage() {
      return (
        <div>
          <h1>Admin Dashboard</h1>
          {/* ... */}
        </div>
      );
    }
    
    // 定义该页面的布局
    DashboardPage.getLayout = function getLayout(page) {
      return <AdminLayout>{page}</AdminLayout>;
    };

    对于不需要特殊布局的页面,它们将默认不使用任何布局,或者你可以提供一个默认布局。

3. App Router 中的布局 (Next.js 13+)

在 Next.js 13 引入的 App Router 中,布局的管理变得更加原生和强大。

  • layout.js 文件:你可以在任何路由段中创建一个 layout.js 文件来定义共享 UI。这个布局会应用于该路由段及其所有子路由。

示例:app/dashboard/layout.js

jsx
// app/dashboard/layout.js
export default function DashboardLayout({ children }) {
  return (
    <section>
      {/* 共享的仪表盘导航 */}
      <nav>Dashboard Nav</nav>
      {children}
    </section>
  );
}

这个布局会自动包裹 app/dashboard/page.js 以及 app/dashboard/settings/page.js 等所有子页面。

总结

  • 组件是构建 UI 的基本单位,应保持独立和可重用。
  • 共享布局可以通过创建一个 Layout 组件并在 _app.js 中使用它来实现。
  • 对于需要多种布局的复杂应用,每页布局模式提供了更大的灵活性。
  • App Router 中,布局通过 layout.js 文件以更结构化的方式进行管理。

在最后一章中,我们将为你提供一些有用的学习资源,帮助你继续深入学习 Next.js。

本站内容仅供学习和研究使用。