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、性能与开发效率可以同时兼得——这正是现代前端工程追求的最优解。
评论(0)
登录 后参与评论。