首页 / Nuxt 4 入门教程 / 图片优化 @nuxt/image

Nuxt 4 入门教程

图片优化 @nuxt/image

本教程共 50 篇 · 第 31 篇 · 更新于 2026-08-08 · 约 8 分钟阅读

NuxtNuxt4图片优化@nuxt/imageNuxtImg性能

本节目标:能给 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.tsmodules。你也能手动装:

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> 要自己写一长串 srcsetsizes,手写既啰嗦又易错;<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.pnghero-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。