Nuxt 3 通过文件系统路由、内置数据获取方法和组合式函数三大机制,极大简化了全栈应用的开发流程。开发者无需手动配置路由表,也不用在客户端和服务端之间频繁切换数据请求逻辑——一切由框架约定自动完成。
自动路由:约定即路由
在 Nuxt 3 中,pages/ 目录下的文件结构直接映射为应用路由。你不需要写任何路由配置,Nuxt 会在构建时扫描该目录,自动生成 Vue Router 的完整配置。
pages/
index.vue → /
about.vue → /about
users/
index.vue → /users
[id].vue → /users/:id (动态路由)
实用要点
- 动态路由:用方括号
[param]命名文件,组件内通过useRoute().params获取参数值。 - 嵌套路由:在目录中放入
index.vue作为父级布局,同级文件即为子路由。 - 路由元信息:在组件中用
definePageMeta设置中间件、布局或权限控制。
<!-- pages/users/[id].vue -->
<script setup>
const route = useRoute()
console.log(route.params.id) // 动态参数
</script>
效果
新增一个页面只需在 pages/ 下新增一个 .vue 文件,无需重启服务即可热更新路由。这种零配置的方式消除了“路由配置与文件结构脱节”的常见痛点。
数据获取:服务端与客户端无缝切换
Nuxt 3 提供了四个按需选择的数据获取函数,覆盖 SSR、CSR 和静态生成的典型场景。
| 函数 | 执行时机 | 适用场景 |
|------|---------|----------|
| useFetch | 服务端 + 客户端(可选) | 通用数据请求,自动处理 SSR 序列化 |
| useAsyncData | 服务端 + 客户端(可选) | 需要组合多个请求或精细控制缓存 |
| $fetch | 按调用位置决定 | 事件处理或点击触发的请求(纯客户端) |
| useLazyFetch / useLazyAsyncData | 同源,但不会阻塞页面导航 | 非关键数据的后台加载 |
典型用法:服务端渲染优先,客户端激活复用数据
<!-- pages/posts.vue -->
<script setup>
// 服务端发起请求,客户端激活时复用服务端缓存的数据,不重复请求
const { data: posts, pending, error } = await useFetch('/api/posts')
</script>
Nuxt 会自动在服务端执行 useFetch,将结果序列化到 HTML 中。客户端激活时直接使用该数据,不会再次发起网络请求,避免了“页面一闪而过由客户端重新加载数据”的经典体验问题。如果你需要在交互时才获取数据(如点击按钮),改用 $fetch 即可。
错误处理与加载状态useFetch 返回 pending(加载中)和 error(错误对象),可以直接在模板中渲染对应的状态界面:
<template>
<div>
<p v-if="pending">加载中...</p>
<p v-else-if="error">加载失败: {{ error.message }}</p>
<ul v-else>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>
刷新数据
调用 refresh() 方法可以主动触发重新拉取数据,适合下拉刷新或条件变动场景。
组合式函数:跨组件复用有状态逻辑
Nuxt 3 深度集成 Vue 3 的组合式 API,并且自带了大量实用的官方组合式函数。它们都是自动导入(Auto Import)的,不需要手动 import,直接使用即可。
常用官方组合式函数
| 函数 | 功能 |
|------|------|
| useRoute() | 获取当前路由对象,包含 params、query、path |
| useRouter() | 编程式导航跳转 |
| useHead() | 动态设置 <head> 中的 title、meta 等 SEO 信息 |
| useCookie() | 读写响应式 Cookie(服务端/客户端同构) |
| useState() | 跨组件、跨页面共享的状态(类似全局 Pinia Store 的轻量版) |
| useRuntimeConfig() | 访问运行时配置(环境变量等) |
自定义组合式函数
你可以将可复用的业务逻辑封装在 composables/ 目录下,文件名以 use 开头,Nuxt 会自动全局导入。
// composables/useWindowSize.js
export function useWindowSize() {
const width = ref(0)
const height = ref(0)
function update() {
width.value = window.innerWidth
height.value = window.innerHeight
}
onMounted(() => {
update()
window.addEventListener('resize', update)
})
onUnmounted(() => window.removeEventListener('resize', update))
return { width, height }
}
在任意组件中直接调用 const { width, height } = useWindowSize(),逻辑隔离清晰且零配置注入。
三者的协作:一个真实开发流程
假设你要开发一个博客文章列表页:
- 自动路由:在
pages/blog/index.vue创建文件,路由自动生效/blog。 - 数据获取:在
script setup中用const { data: articles } = await useFetch('/api/articles')拉取文章列表,服务端渲染首屏内容。 - 状态管理:若需要高亮当前分类,用
useState('activeCategory', () => ref('all'))存储全局状态,配合useRoute().query处理 URL 同步。 - 自定义组合式函数:如果多个页面都有“滚动加载更多”的逻辑,封装
useInfiniteScroll()函数,放在composables/下直接复用。
整个过程你不需要手写路由配置、不用纠结数据是在服务端还是客户端执行,也不用担心全局状态会污染组件。Nuxt 的这套机制让开发者将精力集中在业务功能的实现上,而非框架的拼装细节。