Next.js 提供了强大的 Image 组件来优化图片加载,以及完善的静态资源管理系统。这节课就让我们探索如何使用 Next.js 的 Image 组件,如何管理静态文件,如何优化字体加载,以及如何提升资源的加载性能。

Next.js 提供了一个优化的 Image 组件,它自动处理图片的懒加载、响应式调整、格式优化等功能。使用 Image 组件可以显著提升页面性能。
让我们从一个简单的例子开始:
|// app/components/Hero.tsx import Image from 'next/image'; export default function Hero() { return ( <div> <Image src="/hero.jpg" alt="英雄图片" width={1200} height={600} /> </div> ); }
这个例子展示了 Image 组件的基本用法。我们指定了图片的路径、替代文本、宽度和高度。Image 组件会自动优化图片,只在需要时加载,并生成响应式的图片版本。
注意,width 和 height 属性是必需的(除非使用 fill 属性)。这些属性用于防止布局偏移,提升用户体验。
如果你需要在项目中使用来自外部域名(即非本地 public 文件夹)的图片,Next.js 默认不会允许所有外部资源直接加载。为了保证安全性和性能,必须在项目根目录下的 next.config.mjs 文件中明确声明哪些外部域名是被允许用于图片加载的。
你需要在 images.remotePatterns 数组中配置所需的协议、域名(hostname)以及路径规则(pathname)。这样配置之后,Next.js 的 Image 组件才能安全地渲染这些外链图片。
|// next.config.mjs const nextConfig = { images: { remotePatterns: [ { protocol: 'https', hostname: 'example.com', pathname: '/images/**', }, ], }, }; export default nextConfig;
然后就可以使用外部图片:
|// app/components/ProductImage.tsx import Image from 'next/image'; export default function ProductImage({ src }: { src: string }) { return ( <Image src={`https://example.com/images/${src}`} alt="产品图片" width={500} height
Image 组件会根据页面布局和设备自动生成不同尺寸的响应式图片,以实现更高的加载效率和更佳的视觉体验。你可以通过 sizes 属性,精准控制在不同屏幕宽度或视口条件下,浏览器应该请求多大尺寸的图片。
例如,sizes 支持类似媒体查询的语法,可以为移动端、平板和桌面等不同场景分别指定图片所占视口的比例,帮助浏览器选择最合适的图片资源进行加载,从而减少带宽浪费并提升页面性能:
|// app/components/ResponsiveImage.tsx import Image from 'next/image'; export default function ResponsiveImage() { return ( <Image src="/banner.jpg" alt="横幅图片" width={1920} height={1080} sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" style={{ width: '100%'
在这个例子中,sizes 属性告诉浏览器:在移动设备上(小于 768px)加载全宽图片,在平板设备上(小于 1200px)加载 50% 宽度的图片,在大屏幕上加载 33% 宽度的图片。
有时候,我们希望图片完全覆盖或填满某个区域,这在实现类似 banner、背景、全屏等视觉效果时尤其常见。此时可以借助 Image 组件的 fill 属性,实现图片在其父容器内自适应拉伸或裁剪。
具体用法是:将图片作为绝对定位元素填满父容器(父容器要设置 position: relative,并指定宽高),图片本身则通过 fill 属性进行自动拉伸。你还可以通过 objectFit 属性选择图片填充模式(如 cover、contain、fill 等),以获得期望的视觉效果。
|// app/components/CoverImage.tsx import Image from 'next/image'; export default function CoverImage() { return ( <div style={{ position: 'relative', width: '100%', height: '400px' }}> <Image src="/cover.jpg" alt="封面图片" fill style={{ objectFit: 'cover' }}
使用 fill 时,父容器必须有 position: relative,并且需要指定宽度和高度。objectFit 属性控制图片如何填充容器,可选值有 cover、contain、fill 等。
Next.js 的 Image 组件自动优化图片。它会:
我们也可以通过 priority 属性来标记重要图片,让它们立即加载:
|// app/components/Hero.tsx import Image from 'next/image'; export default function Hero() { return ( <div> <Image src="/hero.jpg" alt="英雄图片" width={1200} height={600} priority /> </div
priority 属性告诉 Next.js 这个图片很重要,应该在页面加载时立即加载,而不是懒加载。这对于首屏图片很有用。
Next.js 的 public 目录用于存放静态文件。放在这个目录下的文件可以通过 URL 直接访问。
比如,如果我们在 public/logo.png 放置了一个文件,可以通过 /logo.png 访问它。
|// app/components/Logo.tsx import Image from 'next/image'; export default function Logo() { return ( <Image src="/logo.png" alt="Logo" width={100} height={100} /> ); }
注意,路径以 / 开头,这表示从 public 目录的根开始。
Next.js 提供了 next/font 来优化字体加载。它自动下载字体文件,生成 CSS,并内联字体数据,减少额外的网络请求。
让我们看一个例子:
|// app/layout.tsx import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'] }); export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="zh" className=
这个例子使用了 Google Fonts 的 Inter 字体。next/font/google 会自动下载字体文件并优化加载。
我们也可以使用本地字体:
|// app/layout.tsx import localFont from 'next/font/local'; const myFont = localFont({ src: './fonts/my-font.woff2', display: 'swap', }); export default function RootLayout({ children, }: { children: React.ReactNode; }) { return (
display: 'swap' 告诉浏览器在字体加载时使用备用字体,字体加载完成后再切换,这样可以避免文字闪烁。
为了更灵活地管理和复用字体,我们可以通过配置 variable 属性,让 Next.js 自动为该字体生成一个 CSS 变量。这样,我们就可以在全局样式或组件中通过该 CSS 变量访问和应用字体,无需在多个地方重复定义字体族。例如:
|// app/layout.tsx import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], variable: '--font-inter', }); export default function RootLayout({ children, }: { children: React.ReactNode; }) { return (
然后在 CSS 中使用:
|// app/globals.css body { font-family: var(--font-inter); }
这样可以在多个地方使用同一个字体,而不需要重复定义。
在实际项目中,为了同时满足不同场景下的排版需求,通常需要同时引入多种字体。例如,我们可能希望正文使用一种易读的无衬线体,而代码块部分则使用更适合编程阅读的等宽字体。Next.js 的内置字体模块允许我们在同一个项目中灵活配置和管理多种字体。
具体实现方式如下:
app/layout.tsx 文件中,从 next/font/google 导入需要的字体,例如 Inter 和 Roboto_Mono。variable 属性,这样 Next.js 会帮我们生成对应的 CSS 变量(如 --font-inter、--font-roboto-mono)。<html> 元素的 className 属性中,将两个字体变量一起传入,这样全局都能访问到这两个变量。app/globals.css 或对应的 CSS 文件中,使用 CSS 变量为页面的不同部分分配字体。例如,整体正文使用 Inter,代码块部分使用 Roboto Mono。这样配置之后,不同类型内容都能精准、方便地应用到相应的字体:
|// app/layout.tsx import { Inter, Roboto_Mono } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], variable: '--font-inter', }); const robotoMono = Roboto_Mono({ subsets: ['latin'], variable: '--font-roboto-mono', }); export default function RootLayout({ children
然后在 CSS 中使用不同的字体:
|// app/globals.css body { font-family: var(--font-inter); } code { font-family: var(--font-roboto-mono); }
对于图标,我们可以直接使用 SVG。Next.js 支持直接导入 SVG 作为 React 组件:
|// app/components/Icon.tsx import IconSvg from './icon.svg'; export default function Icon() { return <IconSvg />; }
或者使用 next/image 来显示 SVG:
|// app/components/Icon.tsx import Image from 'next/image'; export default function Icon() { return ( <Image src="/icon.svg" alt="图标" width={24} height={24} /> ); }
对于关键资源,我们可以使用 next/head 或直接在 HTML 中添加预加载链接。但在 App Router 中,我们可以使用 metadata API:
|// app/layout.tsx export const metadata = { other: { 'preload': '/critical-font.woff2', }, };
或者使用 link 标签:
|// app/layout.tsx export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html> <head> <link rel="preload" href="/critical-font.woff2" as="font" type="font/woff2"
在这一节课,我们探索了 Next.js 中的图片和静态资源管理。我们学习了如何使用 Image 组件优化图片加载,如何管理静态文件,如何优化字体加载,以及如何提升资源的加载性能。
合理使用 Next.js 的资源优化功能可以显著提升应用性能,改善用户体验。Image 组件和 next/font 是 Next.js 提供的强大工具,它们自动处理了很多优化工作,让我们可以专注于构建功能。
在下一节课,我们将学习表单和用户交互,了解如何使用 Server Actions 处理表单提交,如何实现客户端交互,以及如何构建用户友好的表单体验。