NodeJS系列(8)- Next.js 框架 (一) | 安装配置、路由(Routing)、页面布局(Layout)
<p><br>Next.js 是一个用于构建 Web 应用程序的框架。Next.js 是一个用于生产环境的 React 框架,是一个 React 服务端渲染应用框架。<br><br>Next.js 具有同类框架中最佳的 “开发人员体验” 和许多内置功能,它的特点如下:<br><br> (1) 直观的、 基于页面 的路由系统(并支持 动态路由);<br> (2) 预渲染,支持在页面级的 静态生成 (SSG) 和 服务器端渲染 (SSR)<br> (3) 自动代码拆分,提升页面加载速度;<br> (4) 具有经过优化的预取功能的 客户端路由;<br> (5) 内置 CSS 和 Sass 的支持,并支持多数 CSS-in-JS 库;<br> (6) 开发环境支持快速刷新;<br> (7) 利用 Serverless Functions 及 API 路由 构建 API 功能;<br> (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> 操作系统:CentOS 7.9 (x64)<br> NodeJS: 16.20.0<br> NPM: 8.19.4<br> NVM: 0.39.2<br> NextJS: 13.4.12</p>
<h2><br>2. 创建 Next.js 项目</h2>
<p> 安装 create-next-app 脚手架,命令如下:<br><br> # 使用 -g 参数,表示该命令只需在本机上运行一次<br> $ npm install -g create-next-app <br><br> ...<br><br> 使用 create-next-app 命令创建 NextJS 项目,命令如下:</p>
<p> $ 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> 注:在 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> 也可以使用 npx 命令直接创建 NextJS 项目,命令格式如下:<br><br> $ npx create-next-app nextjs-demo<br><br> 注:npx 是 npm 5.2.0 及更高版本中包含的一个命令行工具,用于执行本地安装的或在线安装的 Node.js 包中的命令。npm 主要用于管理和安装依赖包,而 npx 主要用于运行本地或在线安装的包中的命令。</p>
<p> </p>
<h2>3. 运行 Next.js 项目</h2>
<p> <strong>1) 项目目录结构</strong><br><br> 整个项目的目录结构:</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> <strong>2) 启动项目</strong> <br><br> 进入 nextjs-demo 目录安装依赖,命令如下:<br><br> $ npm install</p>
<p> ...<br><br> 开发模式运行,命令如下:<br><br> $ npm run dev </p>
<div class="cnblogs_code">
<pre> > nextjs-demo@0.1.0 dev
> next dev
- ready started server on 0.0.0.0:3000, url: http://localhost:3000<br><br> ...</pre>
</div>
<p> </p>
<p> 生产模式运行,命令如下:<br><br> $ npm run build </p>
<div class="cnblogs_code">
<pre> > nextjs-demo@0.1.0 build
> next build
...</pre>
</div>
<p><br> $ npm run start</p>
<div class="cnblogs_code">
<pre> > nextjs-demo@0.1.0 start
> next start
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
...</pre>
</div>
<p><br> 使用浏览器访问 http://ip:3000,本机上可以访问 http://localhost:3000。<br><br></p>
<h2><br>4. 路由 (Routing)</h2>
<p> 页面路由器 (Page Router) 有一个基于页面概念的文件系统路由器。当一个文件被添加到 src/pages (或 pages) 目录时,它会自动作为路由使用。<br><br> 在 Next.js 中,页面是从 src/pages (或 pages) 目录中的 .js、.jsx、.ts 或 .tsx 文件导出的 React 组件,并且每个页面都根据其文件名与一个路由相关联。<br><br> <strong>1) 文件名路由</strong> <br><br> 在 src/pages 目录下创建 test.js 文件,内容如下: <br> </p>
<div class="cnblogs_code">
<pre> export <span style="color: rgba(0, 0, 255, 1)">default</span> (props) =><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><div>Test Page</div>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> <br> 使用浏览器访问 http://localhost:3000/test,显示内容如下:<br><br> Test Page <br><br> 显然 /test 被路由到 src/pages/test.js 文件,这里的路径是大小写敏感的,即 /TEST 和 /test 不是同一路径。 <br><br> <strong> 2) 索引路由</strong><br><br> 路由将自动将名为 index 的文件映射到 index 所在目录,具体规则如下:<br> <br> src/pages/index.js -> /<br> src/pages/hello/index.js /hello <br><br> 在 src/pages 目录下创建 hello 子目录,并在 hello 目录下创建 index.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre> export <span style="color: rgba(0, 0, 255, 1)">default</span> (props) =><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><div>Hello - Index Page</div>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> <br> 使用浏览器访问 http://localhost:3000/hello,显示内容如下:<br><br> Hello - Index Page <br><br> <strong>3) 嵌套路由 (多级目录+文件名)</strong><br><br> 路由支持嵌套文件,具体规则如下:<br><br> src/pages/hello/world.js -> /hello/world<br> src/pages/hello/nested/router.js -> /hello/nested/router <br><br> 在 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) =><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><div>Hello/nested - router Page</div><span style="color: rgba(0, 0, 0, 1)">
)
}</span></pre>
</div>
<p> <br> 使用浏览器访问 http://localhost:3000/hello/nested/router,显示内容如下:<br><br> Hello/nested - router Page <br><br> <strong>4) 动态路由</strong><br><br> Next.js 支持具有动态路由的页面,具体规则如下:<br> <br> src/pages/hello/.js -> /hello/*<br><br> 在 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> () =><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> <p>Hello: {router.query.id}</p>
<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p><br> 使用浏览器访问 http://localhost:3000/hello/5,显示内容如下:<br><br> Hello: 5 <br><br> <strong>5) API 路由</strong> <br><br> 使用 App Router 的项目,可以直接使用服务器组件或路由处理程序,不需要使用 API 路由。这里的 API 路由,是指在使用了 Page Router 的项目里,在文件夹 src/pages/api 目录中的任何文件,都会被自动映射到 /api/*,并将被视为 API 端点而不是页面。<br> <br> 上文的 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> 使用浏览器访问 http://localhost:3000/api/hello,显示内容如下:<br><br> {"name":"John Doe"}<br><br> API 路由在 next.config.js 中的相关配置属性是 pageExtensions。<br><br></p>
<h2><br>5. 页面布局 (Layout)</h2>
<p> React 模型允许我们将页面解构为一系列组件,其中许多组件经常在页面之间重复使用,比如在每一页上都有相同的导航栏和页脚等。</p>
<h3> 1) App 组件</h3>
<p> Next.js 使用 App 组件来初始化页面。App 组件除了控制页面初始化之外,还能完成如下功能:<br><br> (1) 在页面更改之间创建共享布局<br> (2) 将附加数据注入页面<br> (3) 添加全局 CSS<br><br> <strong>(1) 自定义 App 组件</strong><br> <br> 可以在 src/pages 目录下添加 _app.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 0, 1)">export default ({ Component, pageProps }) => {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <Component {...pageProps} />
}</pre>
</div>
<p><br> 其中 Component 是动态页面(或当前页面),导航切换页面时,Component 都会更改为导航后的新页面。pageProps 是一个带有初始属性的对象,这些属性是通过某种数据获取方法为页面预加载的,否则它就是一个空对象。<br><br> 注:<br><br> (1) 如果 App 组件正在运行,并且添加了自定义 App 组件(即新增了 src/pages/_app.js 文件),则需要重新启动 NextJS 服务。<br> (2) App 组件 不支持的 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。</p>
<p><br> <strong>(2) getInitialProps 属性</strong></p>
<p> 在 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><>
<p>Data: {example}</p>
<Component {...pageProps} />
</>
<span style="color: rgba(0, 0, 0, 1)"> )
}
MyApp.getInitialProps </span>= async (context) =><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> 不建议使用此模式。相反,可以考虑逐步采用 App 路由器,这样可以更容易地获取页面和布局的数据。</p>
<h3> 2) Document 组件</h3>
<p> Document 组件可以更新用于渲染 (render) 页面的 <html> 和 <body> 标记。<br><br> <strong> (1) 自定义 Document 组件</strong><br> <br> 可以在 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><Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p><br> 注:<br> <br> (1) Document 组件仅在服务器上渲染 (render),因此 onClick 这类的事件处理程序不能在此文件中使用。<br> (2) 要正确渲染页面,需要 <Html>、<Head/>、<Main/> 和 <NextScript/>。<br> (3) _document.js 中使用的 <Head/> 组件与 next/head 不同。此处使用的 <Head/> 组件应仅用于所有页面通用的任何 <Head> 代码。对于所有其他情况,如<title>标记,建议在页面或组件中使用 next/head 。<br> (4) <Main/> 之外的 React 组件不会被浏览器初始化。不要在此处添加应用程序逻辑或自定义 CSS(如样式 jsx)。<br> (5) Document 组件不支持的 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。<br><br> <strong> (2) 自定义 renderPage</strong><br><br> 自定义 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 = () =><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) =><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) =><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><Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
<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> 不建议使用此模式。相反,可以考虑逐步采用 App Router,这样可以更容易地获取页面和布局的数据。<br><br> 注: <br><br> (1) 在客户端转换期间,不会调用 _document 中的 getInitialProps。<br> (2) _document 的 ctx 对象等效于在 getInitialProps 中接收到的对象,添加了 renderPage。</p>
<h3><br> 3) 自定义页面布局</h3>
<p> 在上文 nextjs-demo 项目基础上,创建 src/components 目录,这里 components 和 pages 目录在同一级目录中。<br><br> 创建 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><>
<Navbar />
<main>{children}</main>
<Footer />
</>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p><br> 创建 src/components/navbar.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre> export <span style="color: rgba(0, 0, 255, 1)">default</span> () =><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><>
<div>Navbar</div>
</>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p><br> 创建 src/components/footer.js 文件,内容如下:</p>
<div class="cnblogs_code">
<pre> export <span style="color: rgba(0, 0, 255, 1)">default</span> () =><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><>
<div>Footer</div>
</>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<p> 修改 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 }) =><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><Layout>
<Component {...pageProps} />
</Layout>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> </p>
<p> 使用浏览器访问 http://localhost:3000/test,显示内容如下:<br><br> Navbar<br> Test Page<br> Footer</p>
<h3><br> 4) Errors 页面</h3>
<p> <strong>(1) 404 页面</strong><br><br> 404 页面可能经常被访问。服务器为每次访问呈现一个错误页面会增加 Next.js 服务器的负载,这可能导致成本增加和体验缓慢。<br><br> 为了避免上述陷阱,Next.js 默认情况下提供了一个静态 404 页面,而无需添加任何额外的文件。<br><br> 自定义 404 页面,可以在 src/pages 添加 404.js 文件,内容如下:<br><br> export default function Custom404() {<br> return <h1>404 - Page Not Found</h1><br> }<br><br> 注:如果需要在构建时获取数据,可以在此页面中使用 getStaticProps。<br><br> <strong> (2) 500 页面</strong> <br><br> 服务器为每次访问呈现错误页面会增加响应错误的复杂性。为了帮助用户尽快获得对错误的响应,Next.js 默认情况下提供了一个静态 500 页面,而无需添加任何其他文件。<br> <br> 自定义 500 页面,可以在 src/pages 目录下添加 500.js 文件,内容如下:<br> <br> export default function Custom500() {<br> return <h1>500 - Server-side error occurred</h1><br> }<br> <br> 注:如果需要在构建时获取数据,可以在此页面中使用 getStaticProps。<br><br> <strong>(3) Error 组件</strong><br><br> Error 组件同时处理客户端和服务器端的 500 错误。<br> <br> 自定义 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><p><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></p>
<span style="color: rgba(0, 0, 0, 1)"> )
}
Error.getInitialProps </span>= ({ res, err }) =><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> _error.js 仅在生产环境中使用。在开发过程中,一般调用堆栈中得到一个错误,以了解错误的来源。<br><br> <strong>(4) 重用内置错误页</strong><br><br> 要渲染内置错误页面,可以通过导入 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> <Error statusCode={errorCode} />
<span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <div>Next stars: {stars}</div>
}</pre>
</div>
<p> </p>
<p> 注:<br><br> Error 组件不支持 Next.js 数据获取方法,如 getStaticProps 或 getServerSideProps。<br> _error 和 _app 一样,是一个保留的路径名,_error 用于定义错误页面的自定义布局和行为。当访问路径是 /_error 时,会自动跳转到 404 页面。</p>
<p> </p>
<h2>6. 使用 Ant Design</h2>
<p> Ant-Design 是采用 React 封装了一套 Ant Design 的组件库。Ant Design 的模块化设计方式,用户可以快速建立一个新的应用程序,它还提供丰富的 UI 组件和高可定制,用户可以完全按照自己的需求来进行个性化设置。<br><br> Ant Design 支持跨端统一设计,并可以满足开发者因技术栈而异的不同设计习惯,能够帮助他们实现跨端开发的融合,加快项目实施的进度。Ant Design 还提供了丰富的文档,从概念引导到实践指南,用户可以利用文档获取设计新灵感,同时也提升了自己对软件设计,交互和用户体验的认知水平。<br><br> Ant Desing: https://ant.design/index-cn<br><br> <strong>1) 安装 Ant Design</strong> <br><br> 进入 NextJS 项目目录,运行如下命令:<br><br> $ npm install antd<br><br> 命令运行成功后,查看 package.json 文件,在 "dependencies" 部分多了如下内容:</p>
<div class="cnblogs_code">
<pre> {
...
"dependencies": {
"antd": "^4.5.2",
...
}
}</pre>
</div>
<p><br> 以上命令安装了 latest 版的 antd,可以指定安装版本,本文使用 npm install antd@4.5.2 命令安装 Ant Design 4.5.2 。 <br> <br> 也可以先修改 package.json 文件,指定 antd 的版本,比如 "antd": "^4.5.2",再运行 npm install 命令。<br><br> <strong> 2) 使用 antd 组件</strong> <br><br> 在上文 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 }) =><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><Layout>
<Component {...pageProps} />
</Layout>
<span style="color: rgba(0, 0, 0, 1)"> )
}</span></pre>
</div>
<p> 注:添加了 antd/dist/antd.min.css</p>
<p> </p>
<p> 修改 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><HomeOutlined />,
<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><LoginOutlined />,
<span style="color: rgba(0, 0, 0, 1)"> },
];
const Navbar </span>= () =><span style="color: rgba(0, 0, 0, 1)"> {
const </span>= useState('home'<span style="color: rgba(0, 0, 0, 1)">);
const onClick </span>= (e) =><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> <Menu onClick={onClick} selectedKeys={} mode="horizontal" items={items} />;
<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> 以上代码使用了 antd 的 Menu 组件和 Icon 组件,使用浏览器访问 http://localhost:3000/test,显示内容如下:<br><br> Home Login # 菜单<br> Test Page<br> Footer<br><br><br></p><br><br>
来源:https://www.cnblogs.com/tkuang/p/17612546.html
頁:
[1]