图片优化 @nuxt/image
本教程共 50 篇 · 第 31 篇 · 更新于 2026-08-08 · 约 8 分钟阅读
本节目标:能给 Nuxt 项目装上 @nuxt/image,并用
<NuxtImg>输出自动压缩、响应式、懒加载的图片,理解它和 public 目录的关系。
图片往往是网页里最占体积的资源。一张没处理过的高清图动辄几百 KB 甚至几 MB,直接拖慢加载速度。@nuxt/image 是 Nuxt 官方生态里的图片优化模块,它像一个「图片工厂」:你给它原图,它按需生成更小、更合适尺寸的版本,自动选 WebP/AVIF 这类现代格式,还能懒加载。对关心性能的你来说,这是必学的工具。
31-1
最简单的安装方式是让 Nuxt CLI 帮你加模块:
npx nuxi@latest module add image
它会自动把 @nuxt/image 加进 nuxt.config.ts 的 modules。你也能手动装:
npm install @nuxt/image
export default defineNuxtConfig({
modules: ['@nuxt/image'],
})
装好后,<NuxtImg> 和 <NuxtPicture> 两个组件就能直接用了,无需手动导入(Nuxt 会自动导入组件)。
31-2
<NuxtImg> 是原生 <img> 的「升级替代品」,用法几乎一模一样,但背后多了优化。最基础的写法:
<template>
<NuxtImg
src="/img/hero.png"
alt="首页主图"
/>
</template>
只要把 <img> 换成 <NuxtImg>,它就支持原生 <img> 的全部属性。默认情况下,模块会用内置的 ipx 处理器在服务器端把图处理好再吐给浏览器,URL 会变成类似 /_ipx/... 的形式,原图和变换后的图都会被缓存。
Tip第一次在模板里用
<NuxtImg>时,CLI 有时会自动提示帮你安装依赖。若没提示,就按上面手动npm install @nuxt/image即可。
除了压缩和格式,模块还默认帮你做了「懒加载」:图片进入视口附近才真正去加载,首屏之外的图不抢占带宽。你通常不需要额外配置,这是 <NuxtImg> 相对原生 <img> 又一个省心的地方。换句话说,换上 <NuxtImg> 后,你几乎「白拿」了压缩、格式优化、响应式、懒加载四样能力,而这四点恰恰是网页图片性能的关键。对内容站、电商、博客这类图片多的场景,这点改动带来的加载提速往往非常明显。
31-3
给图片定宽高,既能避免布局抖动,也方便优化器生成精确尺寸:
<template>
<NuxtImg
src="/img/hero.png"
width="800"
height="450"
alt="首页主图"
/>
</template>
优化器会按你给的尺寸去缩放原图,而不是让浏览器硬拉。注意这里的 src 指向 public/ 下的文件同样有效——稍后讲它和 public 的关系。
31-4
同样一张图,手机上显示 400px 宽就够了,4K 大屏却可能需要 1200px。让浏览器自己挑最合适的尺寸,就是「响应式图片」。<NuxtImg> 用 sizes 属性描述「不同屏幕下要的宽度」,它会自动生成 srcset,浏览器按视口挑最小够用的那张。
<template>
<NuxtImg
src="/img/hero.png"
sizes="100vw sm:50vw md:400px"
alt="响应式主图"
/>
</template>
意思是:小屏占满视口(100vw),sm 断点起占一半(50vw),md 起固定 400px。模块据此生成多档图片和对应 URL。
对于高清屏(如 Retina,设备像素比 2 或 3),用 densities 指定需要的倍数:
<template>
<NuxtImg
src="/img/avatar.png"
width="80"
height="80"
densities="1x 2x"
alt="头像"
/>
</template>
31-5
现代浏览器都支持 WebP、AVIF,它们比老旧的 JPEG/PNG 小得多。<NuxtImg> 可以通过配置默认输出更省流量的格式。在 nuxt.config.ts 里设置:
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
format: ['webp', 'avif'],
quality: 80,
},
})
这样处理出来的图会优先用 WebP/AVIF,质量压到 80%。你也能在单张图上传 modifiers 做局部变换,比如转灰度:
<template>
<NuxtImg
src="/img/photo.png"
width="800"
:modifiers="{ grayscale: true }"
alt="灰度照片"
/>
</template>
Note这些变换由底层的 Sharp 图像处理库驱动,转换和原图都会在服务端缓存,所以第一次稍慢,之后就很快。
31-6
图片不一定都在你自己的 public/ 里,也可能来自网络(如 Unsplash、图床)。出于安全,模块默认不允许随便拉外部域名的图,你得在 domains 里「白名单」放行:
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
domains: ['picsum.photos', 'images.unsplash.com'],
},
})
<template>
<NuxtImg
src="https://picsum.photos/800/450"
width="800"
height="450"
alt="远程图"
/>
</template>
更进一步,模块支持把图片处理「外包」给专业 CDN,比如 Cloudinary、Vercel、Netlify、Imgix、TwicPics。换 provider 只需改配置,组件写法不变:
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
provider: 'cloudinary',
cloudinary: {
baseURL: 'https://res.cloudinary.com/你的账号/image/upload/',
},
},
})
默认 provider 是 ipx(自带、零成本),生产环境若上了云,换成对应 CDN provider 能进一步减负。
31-7
有些图每次都要同样的尺寸和格式(比如头像永远 80×80 的 WebP),写成预设最省事:
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
presets: {
avatar: {
modifiers: { format: 'webp', width: 80, height: 80 },
},
},
},
})
<template>
<NuxtImg src="/img/user.png" preset="avatar" alt="用户头像" />
</template>
31-8
@nuxt/image 优化的源图通常就放在 public/(上一章讲的目录),因为 public 文件有稳定的 /img/xxx.png URL,模块能直接按这个 URL 取原图再去处理。换句话说:public 负责「存原图、给稳定地址」,@nuxt/image 负责「按请求实时优化出小图」,两者是配合关系,不是替代关系。
Warning不要把需要被 @nuxt/image 优化的图放进
app/assets/。assets 会被构建工具哈希改名,模块按固定 URL 取不到原图。优化类的图放public/(Nuxt 4 下是项目根目录的public/),纯展示、不需要优化的图才考虑app/assets/。
31-9
把 <img> 换成 <NuxtImg> 不是赶时髦。原生 <img> 你得自己操心四件事,而 <NuxtImg> 默认帮你兜住了:
第一,压缩。原图 2MB,直接 <img src> 浏览器就老老实实下载 2MB;<NuxtImg> 让服务端先按目标尺寸压一遍再传更小的图。
第二,格式。原生 <img> 只能用原图格式;<NuxtImg> 能吐 WebP/AVIF,体积可能只剩原来的三分之一。
第三,响应式。原生 <img> 要自己写一长串 srcset 和 sizes,手写既啰嗦又易错;<NuxtImg> 一个 sizes 属性就生成全套。
第四,懒加载。原生 <img> 得加 loading="lazy" 且依赖浏览器支持;<NuxtImg> 默认就懒加载。
代价只是「换个标签名」,换来上面四样。新项目里基本没有理由再手写在 <img> 上堆属性。
31-10
sizes 回答的问题是:这张图在「当前屏幕宽度」下,实际会显示成多宽?浏览器拿到答案,再去 srcset 里挑一张宽度最接近、又不浪费的图。
规则是「从左到右匹配第一个成立的断点」。写法 sizes="100vw sm:50vw md:400px" 拆开看:
100vw:没指定断点的默认值,意思是「占满整个视口宽」。sm:50vw:当屏幕 ≥sm断点(默认 640px)时,占视口一半。md:400px:当屏幕 ≥md(默认 768px)时,固定 400px。
浏览器取「当前视口下第一个满足的」作为目标宽度。比如手机 375px 宽,三个断点都不触发,用 100vw → 目标 375px;平板 800px 宽,命中 md → 目标 400px。NuxtImg 据此生成 hero-400.png、hero-768.png 这种多档图,浏览器再按设备像素比乘上 densities 选最合适那张。
写 sizes 的诀窍:让它尽量贴近图片在布局里的真实显示宽度,别一股脑写 100vw。否则小屏也会下大图,优化就白做了。
31-11
换了 <NuxtImg> 却看不到图,多半是下面几种情况:
- 图放进了
app/assets/。assets 会被打包工具哈希改名,<NuxtImg>按固定 URL 取不到原图。要被优化的图放public/,纯展示、不需要处理的图才进app/assets/。 - 远程图没加白名单。用了
https://xxx的图却忘了在image.domains里放行,会被模块拦下。 - 路径写错。
<NuxtImg>的src相对 public 根,写/img/hero.png对应public/img/hero.png,多写一层前缀或拼错目录都会 404。 - ipx 第一次处理大图稍慢,可能让人误以为坏了,等一两秒再刷新;或者原图本身损坏、格式不被 Sharp 支持。
排错时打开浏览器开发者工具的 Network 面板,看 /_ipx/... 那个请求返回了什么,基本能定位是 404、403 还是 500。
31-12
@nuxt/image 让图片优化变得「几乎无感」:装好模块,把 <img> 换成 <NuxtImg>,它就帮你压缩、转格式、做响应式、懒加载。记住三点:本地要优化的图放 public/;远程图先加 domains 白名单;想要统一效果就配 image 选项或 presets。下一部分我们跨入「服务端能力」,先看怎么用 Nuxt 写自己的 API。