🔍 登录 注册

Nuxt 3 全栈实战:从路由到数据获取的完整指南

Z ZeroIsStart 2026-10-20 前端 👁 1 ⏱ 5min

Nuxt 3 全栈实战:从路由到数据获取的完整指南

Nuxt 3 基于 Vue 3 + Vite 重构,自带 SSR、文件路由、自动导入与服务端能力,是 Vue 生态里"开箱即用"的全栈框架。本文从目录结构、路由、数据获取到部署,系统讲解 Nuxt 3 的核心实践。

一、约定式目录结构

app/
├── pages/           # 文件路由(自动生成路由表)
├── components/      # 组件(自动导入)
├── composables/     # 组合函数(自动导入)
├── layouts/         # 布局(default.vue 为默认)
├── middleware/      # 路由中间件
├── stores/          # Pinia stores
├── app.vue          # 根组件
├── nuxt.config.ts   # Nuxt 配置
└── server/          # Nitro 服务端(API 层)

自动导入是 Nuxt 3 的杀手锏:pages/、components/、composables/ 中的文件无需 import 即可使用,代码显著清爽。

二、文件路由与导航

2.1 动态路由

pages/
├── index.vue                 → /
├── articles/index.vue        → /articles
├── articles/[slug].vue       → /articles/:slug
├── books/[slug]/chapters/[chapterSlug].vue
<!-- pages/articles/[slug].vue -->
<script setup lang="ts">
const route = useRoute()
const slug = route.params.slug       // 读取动态参数
</script>

2.2 导航与路由守卫

<!-- 声明式导航 -->
<NuxtLink :to="`/articles/${article.slug}`">{{ article.title }}</NuxtLink>

<!-- 编程式导航 -->
<script setup>
function go() {
  navigateTo('/articles/hello-world')
}
</script>
// middleware/auth.ts:路由守卫
export default defineNuxtRouteMiddleware((to) => {
  const user = useUserStore()
  if (!user.isLoggedIn) {
    return navigateTo({ path: '/login', query: { redirect: to.fullPath } })
  }
})

三、数据获取:SSR 的核心技能

3.1 useAsyncData / useFetch

<script setup>
// useFetch:简化的数据获取(自动处理 loading、error)
const { data: article, pending, error } = await useFetch(`/api/v1/articles/${slug}`)

// useAsyncData:更灵活(自定义 fetcher)
const { data: articles, refresh } = await useAsyncData(
  'articles-list',                    // 唯一 key,缓存/去重
  () => $fetch('/api/v1/articles', { params: { page } })
)
</script>

关键语义:

  • 服务端执行一次、客户端 hydration 后复用(SSR);
  • 同一 key 的请求自动去重,避免重复拉取;
  • refresh 手动刷新数据。

3.2 登录态的坑:SSR 与客户端状态分离

// 游客视角的登录态信息:SSR 永远未登录
// 正确做法:客户端挂载后再获取
const user = ref<UserProfile | null>(null)
if (process.client) {
  user.value = await $fetch('/api/v1/me')
}

铁律:涉及 cookie/localStorage 的状态不能进 SSR 渲染,否则 hydration 不一致导致闪烁甚至报错。

四、服务端能力:Nitro

Nuxt 3 内置 Nitro 服务端,可以在同一项目写 API:

// server/api/articles/index.ts
export default defineEventHandler(async (event) => {
  const query = getQuery(event)
  return await prisma.article.findMany({
    where: { category: query.category as string },
  })
})

// server/api/articles/[slug].ts
export default defineEventHandler(async (event) => {
  const { slug } = getRouterParams(event)
  return await prisma.article.findUnique({ where: { slug } })
})

Nitro 特性:文件路由(与 pages 同构)、自动处理 JSON、支持中间件与插件、可部署到 Node/Edge/Serverless 多种环境。

五、SSR 渲染模式的选择

| 模式 | 配置 | 特点 | |------|------|------| | SSR | 默认 | 服务端渲染,SEO 好,首屏快 | | SSG | routeRules | 静态生成,CDN 缓存,内容变化不频繁 | | SPA | ssr: false | 纯客户端,适合登录后台 | | 混合 | routeRules 按路由 | 首页 SSG + 文章 SSR + 后台 SPA |

// nuxt.config.ts 混合模式
export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },            // 首页静态化
    '/articles/**': { swr: 3600 },       // 文章缓存 1 小时
    '/admin/**': { ssr: false },         // 后台纯 SPA
  },
})

六、SEO 与性能优化

6.1 SEO 元信息

<script setup>
useSeoMeta({
  title: () => `${article.title} · okgoes`,
  description: () => article.summary,
  ogTitle: () => article.title,
  ogImage: () => article.cover_image_url,
})
</script>

6.2 性能清单

  • 字体与图片:字体子集化、图片懒加载 + width/height 预留空间;
  • 组件懒加载:defineAsyncComponent 或 Nuxt 自动代码分割;
  • 缓存策略:routeRules 配合 CDN,动态与静态分离;
  • 渲染阻塞:避免巨大组件同步渲染拖慢 LCP。

七、常见坑与排查

| 问题 | 原因与解法 | |------|------------| | hydration 不一致 | 客户端才有的状态被服务端渲染,用 process.client 隔离 | | 中文 slug 404 | 路由参数需 encodeURIComponent,统一用 code 或 safeSlug | | 数据重复请求 | useAsyncData 未给 key 或不在顶层调用 | | 401 循环 | 401 时清会话并跳登录,加 redirect 参数 | | 部署后白屏 | 检查服务端渲染报错日志,SSR 错误会白屏 |

结语

Nuxt 3 的价值在于用一个框架统一了前端、SSR 与服务端,让"全栈 Vue"成为可能。掌握约定式路由、数据获取的 SSR 语义与 Nitro 服务端这三块,你就能从"写页面"进阶到"写应用"。再配合 routeRules 的混合渲染,SEO、性能与开发效率可以同时兼得——这正是现代前端工程追求的最优解。

读完了?给作者一点支持

本文采用 CC BY 4.0 协议转载 · © ZeroIsStart

评论(0)

登录 后参与评论。

  • 还没有评论,来抢沙发。

🔗 相关文章