唔得闲 發表於 2023-8-7 20:41:00

NodeJS系列(8)- Next.js 框架 (一) | 安装配置、路由(Routing)、页面布局(Layout)

<p><br>Next.js 是一个用于构建 Web 应用程序的框架。Next.js 是一个用于生产环境的 React 框架,是一个 React 服务端渲染应用框架。<br><br>Next.js 具有同类框架中最佳的 “开发人员体验” 和许多内置功能,它的特点如下:<br><br>&nbsp;&nbsp;&nbsp; (1) 直观的、 基于页面 的路由系统(并支持 动态路由);<br>&nbsp;&nbsp;&nbsp; (2) 预渲染,支持在页面级的 静态生成 (SSG) 和 服务器端渲染 (SSR)<br>&nbsp;&nbsp;&nbsp; (3) 自动代码拆分,提升页面加载速度;<br>&nbsp;&nbsp;&nbsp; (4) 具有经过优化的预取功能的 客户端路由;<br>&nbsp;&nbsp;&nbsp; (5) 内置 CSS 和 Sass 的支持,并支持多数 CSS-in-JS 库;<br>&nbsp;&nbsp;&nbsp; (6) 开发环境支持快速刷新;<br>&nbsp;&nbsp;&nbsp; (7) 利用 Serverless Functions 及 API 路由 构建 API 功能;<br>&nbsp;&nbsp;&nbsp; (8) 完全可扩展;<br><br>Next.js 被用于数以万计的的网站和 Web 应用程序,包括许多世界上许多最大的品牌都在使用 Next.js。<br><br>NextJS: https://nextjs.org/<br>NextJS GitHub: https://github.com/vercel/next.js<br>React: https://www.reactjs.org/ (https://react.dev)<br>React GitHub: https://github.com/facebook/react<br><br></p>
<h2><br>1. 系统环境</h2>
<p>&nbsp;&nbsp;&nbsp; 操作系统:CentOS 7.9 (x64)<br>&nbsp;&nbsp;&nbsp; NodeJS: 16.20.0<br>&nbsp;&nbsp;&nbsp; NPM: 8.19.4<br>&nbsp;&nbsp;&nbsp; NVM: 0.39.2<br>&nbsp;&nbsp;&nbsp; NextJS: 13.4.12</p>
<h2><br>2. 创建 Next.js 项目</h2>
<p>&nbsp;&nbsp;&nbsp; 安装 create-next-app&nbsp; 脚手架,命令如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 使用 -g 参数,表示该命令只需在本机上运行一次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npm install -g create-next-app&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br><br>&nbsp;&nbsp;&nbsp; 使用 create-next-app 命令创建 NextJS 项目,命令如下:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ create-next-app nextjs-demo</p>
<div class="cnblogs_code">
<pre>            √ Would you like to use TypeScript? ... No
            √ Would you like to use ESLint? ... No
            √ Would you like to use Tailwind CSS? ... No
            √ Would you like to use `src/` directory? ... Yes
            √ Would you like to use App Router? (recommended) ... No
            √ Would you like to customize the default import alias? ... Yes
            Creating a new Next.js app in /home/develop/nodejs/nextjs-demo.

            Using npm.

            Initializing project with template: default


            Installing dependencies:
            - react
            - react-dom
            - next


            added 23 packages in 5s
            Initialized a git repository.

            Success! Created nextdemo at /home/develop/nodejs/nextjs-demo</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:在 Next.js 13 之前,Pages Router 是在 Next.jsp 中创建路由的主要方式。它使用直观的文件系统路由器将每个文件映射到一个路由。新版本的 Next.js 仍然支持 Pages Router,Next.js 官方建议迁移到新的 App Router,以利用 React 的最新功能。本文主要介绍基于 Pages Router 的 Web 应用,所以第 5 个选项选了 No,表示选择了 Pages Router。<br><br>&nbsp;&nbsp;&nbsp; 也可以使用 npx 命令直接创建 NextJS 项目,命令格式如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npx create-next-app nextjs-demo<br><br>&nbsp;&nbsp;&nbsp; 注:npx 是 npm 5.2.0 及更高版本中包含的一个命令行工具,用于执行本地安装的或在线安装的 Node.js 包中的命令。npm 主要用于管理和安装依赖包,而 npx 主要用于运行本地或在线安装的包中的命令。</p>
<p>&nbsp;</p>
<h2>3. 运行 Next.js 项目</h2>
<p>&nbsp;&nbsp;&nbsp; <strong>1) 项目目录结构</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 整个项目的目录结构:</p>
<div class="cnblogs_code">
<pre>            ├── public
            │   ├── favicon.ico   # Favicon
            │   ├── next.svg
            │   └── vercel.svg
            ├── src
            │   ├── pages               # Page Router
            │   │   ├── api
            │   │   │   └── hello.js
            │   │   ├── _app.js
            │   │   ├── _document.js
            │   │   └── index.js      # home Page
            │   │
            │   └── styles
            │       ├── globals.css
            │       └── Home.module.css
            │
            ├── jsconfig.json         # JavaScript 配置文件
            ├── next.config.js          # Next.js 配置文件
            ├── package-lock.json       # 项目依赖和脚本(锁定),运行 npm install 后自动生成
            ├── package.json            # 项目依赖和脚本
            └── README.md</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp; <strong>2) 启动项目</strong> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 进入 nextjs-demo 目录安装依赖,命令如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npm install</p>
<p>   &nbsp;&nbsp;&nbsp;&nbsp; ...<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开发模式运行,命令如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npm run dev </p>
<div class="cnblogs_code">
<pre>                &gt; nextjs-demo@0.1.0 dev
                &gt; next dev

                - ready started server on 0.0.0.0:3000, url: http://localhost:3000<br><br>                ...</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 生产模式运行,命令如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npm run build </p>
<div class="cnblogs_code">
<pre>                &gt; nextjs-demo@0.1.0 build
                &gt; next build
               
                ...</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npm run start</p>
<div class="cnblogs_code">
<pre>                &gt; nextjs-demo@0.1.0 start
                &gt; next start

                - ready started server on 0.0.0.0:3000, url: http://localhost:3000

                ...</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://ip:3000,本机上可以访问 http://localhost:3000。<br><br></p>
<h2><br>4. 路由 (Routing)</h2>
<p>&nbsp;&nbsp;&nbsp; 页面路由器 (Page Router) 有一个基于页面概念的文件系统路由器。当一个文件被添加到 src/pages (或 pages) 目录时,它会自动作为路由使用。<br><br>&nbsp;&nbsp;&nbsp; 在 Next.js 中,页面是从 src/pages (或 pages) 目录中的 .js、.jsx、.ts 或 .tsx 文件导出的 React 组件,并且每个页面都根据其文件名与一个路由相关联。<br><br>&nbsp;&nbsp;&nbsp; <strong>1) 文件名路由</strong> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在 src/pages 目录下创建 test.js 文件,内容如下:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</p>
<div class="cnblogs_code">
<pre>            export <span style="color: rgba(0, 0, 255, 1)">default</span> (props) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;div&gt;Test Page&lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://localhost:3000/test,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test Page <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 显然 /test 被路由到 src/pages/test.js 文件,这里的路径是大小写敏感的,即 /TEST 和 /test 不是同一路径。 <br><br>&nbsp;&nbsp;&nbsp;<strong> 2) 索引路由</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 路由将自动将名为 index 的文件映射到 index 所在目录,具体规则如下:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/pages/index.js -&gt;&nbsp; /<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/pages/hello/index.js&nbsp; /hello <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在 src/pages 目录下创建 hello 子目录,并在 hello 目录下创建 index.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            export <span style="color: rgba(0, 0, 255, 1)">default</span> (props) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;div&gt;Hello - Index Page&lt;/div&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://localhost:3000/hello,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hello - Index Page&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br><br>&nbsp;&nbsp;&nbsp; <strong>3) 嵌套路由 (多级目录+文件名)</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 路由支持嵌套文件,具体规则如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/pages/hello/world.js&nbsp; -&gt; /hello/world<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/pages/hello/nested/router.js -&gt; /hello/nested/router <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在 src/pages 目录下创建 hello/nested 两级子目录,并在 nested 目录下创建 router.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            export <span style="color: rgba(0, 0, 255, 1)">default</span> (props) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;div&gt;Hello/nested - router Page&lt;/div&gt;<span style="color: rgba(0, 0, 0, 1)">
                )
            }</span></pre>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://localhost:3000/hello/nested/router,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hello/nested - router Page&nbsp; &nbsp;<br><br>&nbsp;&nbsp;&nbsp; <strong>4) 动态路由</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Next.js 支持具有动态路由的页面,具体规则如下:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; src/pages/hello/.js&nbsp; -&gt; /hello/*<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在 src/pages/hello 目录下创建 ".js" 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            import { useRouter } from 'next/router'<span style="color: rgba(0, 0, 0, 1)">

            export </span><span style="color: rgba(0, 0, 255, 1)">default</span> () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {

                const router </span>=<span style="color: rgba(0, 0, 0, 1)"> useRouter()
                </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;p&gt;Hello: {router.query.id}&lt;/p&gt;
<span style="color: rgba(0, 0, 0, 1)">
            }</span></pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://localhost:3000/hello/5,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Hello: 5 &nbsp;<br><br>&nbsp;&nbsp;&nbsp; <strong>5) API 路由</strong> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用 App Router 的项目,可以直接使用服务器组件或路由处理程序,不需要使用 API 路由。这里的 API 路由,是指在使用了 Page Router 的项目里,在文件夹 src/pages/api 目录中的任何文件,都会被自动映射到 /api/*,并将被视为 API 端点而不是页面。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 上文的 nextjs-demo 项目里,create-next-app 命令自动创建了文件 src/pages/api/hello.js,它就是一个 API 端点,内容如下:</p>
<div class="cnblogs_code">
<pre>            <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Next.js API route support: https://nextjs.org/docs/api-routes/introduction</span>
<span style="color: rgba(0, 0, 0, 1)">
            export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> handler(req, res) {
                res.status(</span>200).json({ name: 'John Doe'<span style="color: rgba(0, 0, 0, 1)"> })
            }</span></pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://localhost:3000/api/hello,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {"name":"John Doe"}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; API 路由在 next.config.js 中的相关配置属性是 pageExtensions。<br><br></p>
<h2><br>5. 页面布局 (Layout)</h2>
<p>&nbsp;&nbsp;&nbsp; React 模型允许我们将页面解构为一系列组件,其中许多组件经常在页面之间重复使用,比如在每一页上都有相同的导航栏和页脚等。</p>
<h3>&nbsp;&nbsp;&nbsp; 1) App 组件</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Next.js 使用 App 组件来初始化页面。App 组件除了控制页面初始化之外,还能完成如下功能:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) 在页面更改之间创建共享布局<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) 将附加数据注入页面<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3) 添加全局 CSS<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>(1) 自定义 App 组件</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以在 src/pages 目录下添加 _app.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>                <span style="color: rgba(0, 0, 0, 1)">export default ({ Component, pageProps }) =&gt; {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;Component {...pageProps} /&gt;
                }</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其中 Component 是动态页面(或当前页面),导航切换页面时,Component 都会更改为导航后的新页面。pageProps 是一个带有初始属性的对象,这些属性是通过某种数据获取方法为页面预加载的,否则它就是一个空对象。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) 如果 App 组件正在运行,并且添加了自定义 App 组件(即新增了 src/pages/_app.js 文件),则需要重新启动 NextJS 服务。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) App 组件 不支持的 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。</p>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>(2) getInitialProps 属性</strong></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在 App 组件中可以使用 getInitialProps 将对没有 getStaticProps 的页面禁用自动静态优化。</p>
<div class="cnblogs_code">
<pre>                import App from 'next/app'<span style="color: rgba(0, 0, 0, 1)">
               
                export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> MyApp({ Component, pageProps, example }) {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                        </span>&lt;&gt;
                        &lt;p&gt;Data: {example}&lt;/p&gt;
                        &lt;Component {...pageProps} /&gt;
                        &lt;/&gt;
<span style="color: rgba(0, 0, 0, 1)">                  )
                }
               
                MyApp.getInitialProps </span>= async (context) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  const ctx </span>=<span style="color: rgba(0, 0, 0, 1)"> await App.getInitialProps(context)
                  
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span> { ...ctx, example: 'data'<span style="color: rgba(0, 0, 0, 1)"> }
                }</span></pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不建议使用此模式。相反,可以考虑逐步采用 App 路由器,这样可以更容易地获取页面和布局的数据。</p>
<h3>&nbsp;&nbsp;&nbsp; 2) Document 组件</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Document 组件可以更新用于渲染 (render) 页面的 &lt;html&gt; 和 &lt;body&gt; 标记。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong> (1) 自定义 Document 组件</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以在 src/pages 目录下添加 _document.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>                import { Html, Head, Main, NextScript } from 'next/document'<span style="color: rgba(0, 0, 0, 1)">
               
                export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Document() {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                        </span>&lt;Html lang="en"&gt;
                        &lt;Head /&gt;
                        &lt;body&gt;
                            &lt;Main /&gt;
                            &lt;NextScript /&gt;
                        &lt;/body&gt;
                        &lt;/Html&gt;
<span style="color: rgba(0, 0, 0, 1)">                  )
                }</span></pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) Document 组件仅在服务器上渲染 (render),因此 onClick 这类的事件处理程序不能在此文件中使用。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) 要正确渲染页面,需要 &lt;Html&gt;、&lt;Head/&gt;、&lt;Main/&gt; 和 &lt;NextScript/&gt;。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (3) _document.js 中使用的 &lt;Head/&gt; 组件与 next/head 不同。此处使用的 &lt;Head/&gt; 组件应仅用于所有页面通用的任何 &lt;Head&gt; 代码。对于所有其他情况,如<title>标记,建议在页面或组件中使用 next/head 。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (4) <Main/> 之外的 React 组件不会被浏览器初始化。不要在此处添加应用程序逻辑或自定义 CSS(如样式 jsx)。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (5) Document 组件不支持的 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong> (2) 自定义 renderPage</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自定义 renderPage 是高级选项,只有在需要 CSS-in-JS 等库来支持服务器端渲染时才需要,对于内置样式的 jsx 支持来说是不需要的。</p>
<div class="cnblogs_code">
<pre>                import Document, { Html, Head, Main, NextScript } from 'next/document'<span style="color: rgba(0, 0, 0, 1)">
                  
                class MyDocument extends Document {
                  static async getInitialProps(ctx) {
                        const originalRenderPage </span>=<span style="color: rgba(0, 0, 0, 1)"> ctx.renderPage
                  
                        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Run the React rendering logic synchronously</span>
                        ctx.renderPage = () =&gt;<span style="color: rgba(0, 0, 0, 1)">
                        originalRenderPage({
                            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Useful for wrapping the whole react tree</span>
                            enhanceApp: (App) =&gt;<span style="color: rgba(0, 0, 0, 1)"> App,
                            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Useful for wrapping in a per-page basis</span>
                            enhanceComponent: (Component) =&gt;<span style="color: rgba(0, 0, 0, 1)"> Component,
                        })
                  
                        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Run the parent `getInitialProps`, it now includes the custom `renderPage`</span>
                        const initialProps =<span style="color: rgba(0, 0, 0, 1)"> await Document.getInitialProps(ctx)
                  
                        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> initialProps
                  }
                  
                  render() {
                        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                            </span>&lt;Html lang="en"&gt;
                              &lt;Head /&gt;
                              &lt;body&gt;
                              &lt;Main /&gt;
                              &lt;NextScript /&gt;
                              &lt;/body&gt;
                            &lt;/Html&gt;
<span style="color: rgba(0, 0, 0, 1)">                        )
                  }
                }

                export </span><span style="color: rgba(0, 0, 255, 1)">default</span> MyDocument</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不建议使用此模式。相反,可以考虑逐步采用 App Router,这样可以更容易地获取页面和布局的数据。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注: <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) 在客户端转换期间,不会调用 _document 中的 getInitialProps。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) _document 的 ctx 对象等效于在 getInitialProps 中接收到的对象,添加了 renderPage。</p>
<h3><br>&nbsp;&nbsp;&nbsp; 3) 自定义页面布局</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上文 nextjs-demo 项目基础上,创建 src/components 目录,这里 components 和 pages 目录在同一级目录中。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建 src/components/layout.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            import Navbar from './navbar'<span style="color: rgba(0, 0, 0, 1)">
            import Footer from </span>'./footer'<span style="color: rgba(0, 0, 0, 1)">
            
            export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Layout({ children }) {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;&gt;
                        &lt;Navbar /&gt;
                        &lt;main&gt;{children}&lt;/main&gt;
                        &lt;Footer /&gt;
                  &lt;/&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建 src/components/navbar.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            export <span style="color: rgba(0, 0, 255, 1)">default</span> () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;&gt;
                        &lt;div&gt;Navbar&lt;/div&gt;
                  &lt;/&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 创建 src/components/footer.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            export <span style="color: rgba(0, 0, 255, 1)">default</span> () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;&gt;
                        &lt;div&gt;Footer&lt;/div&gt;
                  &lt;/&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改 src/pages/_app.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            import Layout from '../components/layout'<span style="color: rgba(0, 0, 0, 1)">

            export </span><span style="color: rgba(0, 0, 255, 1)">default</span> ({ Component, pageProps }) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;Layout&gt;
                        &lt;Component {...pageProps} /&gt;
                  &lt;/Layout&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用浏览器访问 http://localhost:3000/test,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Navbar<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test Page<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Footer</p>
<h3><br>&nbsp;&nbsp;&nbsp; 4) Errors 页面</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>(1) 404 页面</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 404 页面可能经常被访问。服务器为每次访问呈现一个错误页面会增加 Next.js 服务器的负载,这可能导致成本增加和体验缓慢。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了避免上述陷阱,Next.js 默认情况下提供了一个静态 404 页面,而无需添加任何额外的文件。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自定义 404 页面,可以在 src/pages 添加 404.js 文件,内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; export default function Custom404() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &lt;h1&gt;404 - Page Not Found&lt;/h1&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:如果需要在构建时获取数据,可以在此页面中使用 getStaticProps。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong> (2) 500 页面</strong> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 服务器为每次访问呈现错误页面会增加响应错误的复杂性。为了帮助用户尽快获得对错误的响应,Next.js 默认情况下提供了一个静态 500 页面,而无需添加任何其他文件。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自定义 500 页面,可以在 src/pages 目录下添加 500.js 文件,内容如下:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; export default function Custom500() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &lt;h1&gt;500 - Server-side error occurred&lt;/h1&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:如果需要在构建时获取数据,可以在此页面中使用 getStaticProps。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>(3) Error 组件</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Error 组件同时处理客户端和服务器端的 500 错误。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 自定义 Error 组件,可以在 src/pages 目录下添加 _error.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>                <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Error({ statusCode }) {
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                        </span>&lt;p&gt;<span style="color: rgba(0, 0, 0, 1)">
                        {statusCode
                            </span>?<span style="color: rgba(0, 0, 0, 1)"> `An error ${statusCode} occurred on server`
                            : </span>'An error occurred on client'<span style="color: rgba(0, 0, 0, 1)">}
                        </span>&lt;/p&gt;
<span style="color: rgba(0, 0, 0, 1)">                  )
                }
               
                Error.getInitialProps </span>= ({ res, err }) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  const statusCode </span>= res ? res.statusCode : err ? err.statusCode : 404
                  <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> { statusCode }
                }

                export </span><span style="color: rgba(0, 0, 255, 1)">default</span> Error</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _error.js 仅在生产环境中使用。在开发过程中,一般调用堆栈中得到一个错误,以了解错误的来源。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>(4) 重用内置错误页</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要渲染内置错误页面,可以通过导入 Error 组件,格式如下:</p>
<div class="cnblogs_code">
<pre>                import Error from 'next/error'<span style="color: rgba(0, 0, 0, 1)">
   
                export async </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getServerSideProps() {
                  const res </span>= await fetch('https://api.github.com/repos/vercel/next.js'<span style="color: rgba(0, 0, 0, 1)">)
                  const errorCode </span>= res.ok ? <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)"> : res.status
                  const json </span>=<span style="color: rgba(0, 0, 0, 1)"> await res.json()
               
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
                        props: { errorCode, stars: json.stargazers_count },
                  }
                }
               
                export </span><span style="color: rgba(0, 0, 255, 1)">default</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Page({ errorCode, stars }) {
                  </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (errorCode) {
                        </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;Error statusCode={errorCode} /&gt;
<span style="color: rgba(0, 0, 0, 1)">                  }
                  
                  </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;div&gt;Next stars: {stars}&lt;/div&gt;
                }</pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Error 组件不支持 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _error 和 _app 一样,是一个保留的路径名,_error 用于定义错误页面的自定义布局和行为。当访问路径是 /_error 时,会自动跳转到 404 页面。</p>
<p>&nbsp;</p>
<h2>6. 使用 Ant Design</h2>
<p>&nbsp;&nbsp;&nbsp; Ant-Design 是采用 React 封装了一套 Ant Design 的组件库。Ant Design 的模块化设计方式,用户可以快速建立一个新的应用程序,它还提供丰富的 UI 组件和高可定制,用户可以完全按照自己的需求来进行个性化设置。<br><br>&nbsp;&nbsp;&nbsp; Ant Design 支持跨端统一设计,并可以满足开发者因技术栈而异的不同设计习惯,能够帮助他们实现跨端开发的融合,加快项目实施的进度。Ant Design 还提供了丰富的文档,从概念引导到实践指南,用户可以利用文档获取设计新灵感,同时也提升了自己对软件设计,交互和用户体验的认知水平。<br><br>&nbsp;&nbsp;&nbsp; Ant Desing: https://ant.design/index-cn<br><br>&nbsp;&nbsp;&nbsp; <strong>1) 安装 Ant Design</strong> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 进入 NextJS 项目目录,运行如下命令:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ npm install antd<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 命令运行成功后,查看 package.json 文件,在 "dependencies" 部分多了如下内容:</p>
<div class="cnblogs_code">
<pre>            {
                ...

                "dependencies": {
                  "antd": "^4.5.2",
                  ...

                }
            }</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上命令安装了 latest 版的 antd,可以指定安装版本,本文使用 npm install antd@4.5.2 命令安装 Ant Design 4.5.2 。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 也可以先修改 package.json 文件,指定 antd 的版本,比如 "antd": "^4.5.2",再运行 npm install 命令。<br><br>&nbsp;&nbsp;&nbsp;<strong> 2) 使用 antd 组件</strong> <br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在上文 nextjs-demo 项目基础上,修改 src/pages/_app.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            import 'antd/dist/antd.min.css'<span style="color: rgba(0, 0, 0, 1)">;
            import Layout from </span>'../components/layout'<span style="color: rgba(0, 0, 0, 1)">

            export </span><span style="color: rgba(0, 0, 255, 1)">default</span> ({ Component, pageProps }) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> (
                  </span>&lt;Layout&gt;
                        &lt;Component {...pageProps} /&gt;
                  &lt;/Layout&gt;
<span style="color: rgba(0, 0, 0, 1)">                )
            }</span></pre>
</div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注:添加了 antd/dist/antd.min.css</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改 src/components/navbar.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre>            import React, { useState } from 'react'<span style="color: rgba(0, 0, 0, 1)">;
            import { HomeOutlined, LoginOutlined, SettingOutlined } from </span>'@ant-design/icons'<span style="color: rgba(0, 0, 0, 1)">;
            import { Menu } from </span>'antd'<span style="color: rgba(0, 0, 0, 1)">;

            const items </span>=<span style="color: rgba(0, 0, 0, 1)"> [
                {
                  label: </span>'Home'<span style="color: rgba(0, 0, 0, 1)">,
                  key: </span>'home'<span style="color: rgba(0, 0, 0, 1)">,
                  icon: </span>&lt;HomeOutlined /&gt;,
<span style="color: rgba(0, 0, 0, 1)">                },
                {
                  label: </span>'Login'<span style="color: rgba(0, 0, 0, 1)">,
                  key: </span>'login'<span style="color: rgba(0, 0, 0, 1)">,
                  icon: </span>&lt;LoginOutlined /&gt;,
<span style="color: rgba(0, 0, 0, 1)">                },
            ];

            const Navbar </span>= () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                const </span>= useState('home'<span style="color: rgba(0, 0, 0, 1)">);

                const onClick </span>= (e) =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
                  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">console.log('click ', e);</span>
<span style="color: rgba(0, 0, 0, 1)">                  setCurrent(e.key);
                };
               
                </span><span style="color: rgba(0, 0, 255, 1)">return</span> &lt;Menu onClick={onClick} selectedKeys={} mode="horizontal" items={items} /&gt;;
<span style="color: rgba(0, 0, 0, 1)">            };

            export </span><span style="color: rgba(0, 0, 255, 1)">default</span> Navbar;</pre>
</div>
<p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 以上代码使用了 antd 的 Menu 组件和 Icon 组件,使用浏览器访问 http://localhost:3000/test,显示内容如下:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Home&nbsp; Login&nbsp;&nbsp;&nbsp;&nbsp; # 菜单<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Test Page<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Footer<br><br><br></p><br><br>
来源:https://www.cnblogs.com/tkuang/p/17612546.html
頁: [1]
查看完整版本: NodeJS系列(8)- Next.js 框架 (一) | 安装配置、路由(Routing)、页面布局(Layout)