文章目录
- 前言
- 目录结构
- 样式方案
- 正常引入样式文件
- Tailwind方案
- CSS Modules方案
- clsx方案
- 文字和图片优化
- 文字
- 图片
- Pages和Layout的机制
- Pages
- Layout
- 通过Link组件改变路由并且拆分打包
- 提供Hooks
- 通过Vercel创建数据
- 未完待续...
前言
对于那些对Next.js一无所知的前端伙伴来说,最佳的快速入门方法无疑是官方提供的交互式入门教程文档。尽管如此,由于官方教程至今未提供中文版本,这无疑增加了中文用户的学习难度。为了帮助大家节省宝贵的时间,我决定亲自深入学习这些材料,并将我所学到的关键信息整理成文。通过阅读我的文章,你也能迅速掌握Next.js的核心要点。
当然学Next.js之前你必须会CRA创建的React项目。
官方入门文档地址:https://nextjs.org/learn/dashboard-app/getting-started
文档如果有错误欢迎指正!
目录结构
如何去初始化一个Next.js项目我就不记录了,很简单。我们还是先看目录结构吧。
初始化工程的目录为:
/app
这个文件夹里放的是我们开发中大部分手写的代码。内部还可以继续细化为:
/app/lib
放js文件,例如一些工具函数,API文件等/app/ui
放组件,例如公共组件、业务组件等
/public
放静态资源,例如图片
/script
放一些数据有关的脚本
/next.config.mjs
在里头可以添加或者修改Webpack设置
其他文件咱们下面讲到对应章节再补充说明~
样式方案
Next对样式的编写提供和推荐了一些方案。
正常引入样式文件
Next给默认设置了路径别名,所以你只需要这样引入样式文件:
import '@/app/ui/global.css';
Tailwind方案
这个库有多火就不说了,不是文章重点学习部分,大概意思就是这个库帮你编写了很多类名的css样式,例如你想要某个h1标签的文字颜色为蓝色且字重为500,那么你就可以这样写:
<h1 className="text-blue-500">I'm blue!</h1>
这样就会自动加上css规则。
感兴趣的自己去看吧,官方文档地址为:https://tailwindcss.com/
CSS Modules方案
这个是CRA创建时默认的CSS隔离方案,就不多说了。
clsx方案
这个库就是方便我们在写class的时候做一些条件判断,例如文档中的例子:
import clsx from 'clsx';export default function InvoiceStatus({ status }: { status: string }) {return (<spanclassName={clsx('inline-flex items-center rounded-full px-2 py-1 text-sm',{'bg-gray-100 text-gray-500': status === 'pending','bg-green-500 text-white': status === 'paid',},)}>// ...
)}
是不是比写什么三元表达式清晰很多。感兴趣的可以查看官方文档:https://www.npmjs.com/package/clsx
综上所述,在Next应用中,使用这些样式方案基本能满足我们的需求了。
文字和图片优化
Next自动的对文字和图片做了很好的优化,减少我们平时对这方面的处理工作。
文字
假如我们需要用自定义的字体,那么会有两个问题:
- 页面第一次加载静态资源的时候,需要拉取和加载自定义字体文件。
- 一旦文字文件被解析,页面将经历一个文字替换的过程。然而,由于自定义字体的行高、尺寸和字重与默认字体不同,从默认字体切换到自定义字体时,页面的布局可能会出现偏移。
Next帮我们处理了上述的问题,并且能够做到第一次加载页面不会拉取字体文件的同时,页面直接显示的就是我们的自定义字体。
做法是,首先创建一个文件/app/ui/fonts.ts
来引入教程给我们预装好的字体文件:
import { Inter, Lusitana } from 'next/font/google'; // 如果是我们自己的字体如何引入?这点我后续有空了尝试下,先按照教材的理解即可export const inter = Inter({ subsets: ['latin'] }); // 这个意思是从这个字体中提取latin这一个模块的字体export const lusitana = Lusitana({ // 还可以设定一些属性weight: ['400', '700'],subsets: ['latin'],
});
然后我们给全局的文字替换成我们自定义的latin字体(好像是替换英文和阿拉伯数字),只需要在/app/layout.tsx
中引入并使用:
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';export default function RootLayout({children,
}: {children: React.ReactNode;
}) {return (<html lang="en"><body className={`${inter.className} antialiased`}>{children}</body></html>);
}
同时官方还推荐使用Tailwind的antialiased类名,让文字看起来更加平滑清晰。在其他子组件使用也是一样的方式。
字体属性的设定有很多,具体可以参考官方文档:https://nextjs.org/docs/app/api-reference/components/font#font-function-arguments
还有文档中提到好像有些属性对谷歌某些字体是没有用的,具体要上谷歌字体官网上去查看(需翻墙):https://fonts.google.com/
图片
首先图片资源官方要求放在/public
目录里。Next提供了Image组件供我们使用,例如:
import Image from 'next/image';export default function Page() {return (// ...<div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12"><Imagesrc="/hero-desktop.png"width={1000}height={760}className="hidden md:block"alt="Screenshots of the dashboard project showing desktop version"/></div>//...);
}
通过这种使用方式,Next会帮我们做好几件事:
- 图片从无到加载出来的过程,页面布局不会出现变化
- 能够适配不同视口的大小
- 自带懒加载
- 如果浏览器支持webp,自动提供webp格式
不过我看这个设备屏幕大小适配的问题是通过Tailwind的hidden md:block
去解决的?默认隐藏,当视口达到设定的md大小就显示。这点我以后有空验证下。
Pages和Layout的机制
Pages
Next设置了一个由文件结构决定路由地址的机制。例如文章中给的例子:
这个路由会顺着文件夹里的invoices中找到page.ts
文件,文件里面就写组件代码即可,会自动的渲染到页面上。
所以当页面创建多了后,关系参考如下:
看明白了吧~
Layout
这个组件的作用就是可以把子页面的page组件嵌套在里面,你可以这么理解,Next的路由文件查找机制其实是这样的:
- 首先沿着路由地址一路过一遍文件夹,例如url=
/dashboard/invoices
- 如果一路都是page.ts,那么找invoices里的page.tsx当做对应的页面。
- 如果路上有layout.tsx,那么其实是把layout.tsx当做对应的父级页面,然后layout.tsx里的children props变量就是子层级文件夹里page.tsx这个组件。这样page.tsx被嵌在layout.tsx显示在页面上。
来看看layout.tsx代码官方的示例:
import SideNav from '@/app/ui/dashboard/sidenav';export default function Layout({ children }: { children: React.ReactNode }) {return (<div className="flex h-screen flex-col md:flex-row md:overflow-hidden"><div className="w-full flex-none md:w-64"><SideNav /> // 公共组件</div><div className="flex-grow p-6 md:overflow-y-auto md:p-12">{children}</div> // = page.tsx</div>);
}
同理其他子页面也是一样的,梳理他们之间的关系如下:
采用这种方式渲染页面可以实现当子组件更新时,父组件无需更新的效果。
所以我的理解是,当你一个页面需要嵌套子组件的时候,就适合用layout组件,当然最大的layout组件在/app
里,和他平级的page.ts应该是嵌套在layout组件里(有空时我去验证下)。
通过Link组件改变路由并且拆分打包
Next给我们提供了Link组件去修改路由地址,使用方式:
import Link from 'next/link';// ...export default function NavLinks() {return (<>{links.map((link) => {const LinkIcon = link.icon;return (<Linkkey={link.name}href={link.href}className="..."><LinkIcon className="w-6" /><p className="hidden md:block">{link.name}</p></Link>);})}</>);
}
这个组件的好处是:Next打包的时候,会自动的通过路由关系去拆分文件,并且不会一下子全部拉取。如果当前页面有Link组件,那么会在背后偷偷预拉取对应的组件代码,等用户点击后直接渲染。
提供Hooks
Next提供了很多hooks供我们使用,例如与路由有关的示例:
'use client'; // 这个意思好像是说这个文件只在浏览器端加载,不作为SSRimport { usePathname } from 'next/navigation';export default function NavLinks() {const pathname = usePathname(); // 获取路由地址// ...
}
// ...
通过Vercel创建数据
首先我们要知道什么是Vercel,这里我找AI介绍了下:
Vercel 是一个平台,提供静态和 Jamstack网站的托管服务。它支持多种前端框架,如Next.js、Nuxt.js、Gatsby等,并且能够实现快速部署、服务器端渲染和自动化的性能优化。Vercel 通过其全球分布式的边缘网络(Edge Network)来加速内容的交付,确保用户能够快速加载网站内容。
Vercel 还提供了集成的连续部署功能,允许开发者在代码推送至GitHub、GitLab或Bitbucket等版本控制系统后自动构建和部署网站。此外,Vercel 还提供了一些高级功能,如路由、重写规则、环境变量管理以及HTTPS证书等,使得开发者可以轻松管理他们的网站。
咱们这个Next.js也是属于Vercel下的!
首先咱们把我们的Next应用推到自己的github仓库。
然后去Vercel网站创建账号,把github上的仓库关联到Vercel中,然后选中我们的Next应用仓库,导入:
接着部署:
成功后会有一个这样的页面:
如果出现部署失败,基本上问题就是要去修改一个文件的配置tsconfig.json
:
"baseUrl": '.',"paths": {"@/*" : ["./*"],"@/app/*": ["app/*"]}