Nuxt.js数据获取基础 #
一、数据获取概述 #
Nuxt.js 提供了强大的数据获取能力,支持服务端渲染(SSR)和客户端渲染(CSR)场景。主要使用 useFetch 和 useAsyncData 组合式函数。
1.1 数据获取方式 #
| 方式 | 说明 | 适用场景 |
|---|---|---|
useFetch |
简化的数据获取 | 大多数场景 |
useAsyncData |
更灵活的数据获取 | 复杂场景 |
$fetch |
直接请求 | 事件处理、API调用 |
useLazyFetch |
懒加载获取 | 非关键数据 |
二、useFetch #
2.1 基本用法 #
vue
<script setup lang="ts">
const { data, pending, error, refresh } = await useFetch('/api/users')
</script>
<template>
<div v-if="pending">加载中...</div>
<div v-else-if="error">加载失败: {{ error.message }}</div>
<div v-else>
<div v-for="user in data" :key="user.id">
{{ user.name }}
</div>
</div>
</template>
2.2 返回值 #
| 属性 | 类型 | 说明 |
|---|---|---|
data |
Ref | 响应式数据 |
pending |
Ref |
是否正在加载 |
error |
Ref<Error | null> |
refresh |
Function | 重新获取数据 |
execute |
Function | 执行请求(immediate: false时) |
2.3 请求选项 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: {
name: '张三',
email: 'zhang@example.com'
},
query: {
page: 1,
limit: 10
},
params: {
id: 123
}
})
</script>
2.4 响应式URL #
vue
<script setup lang="ts">
const page = ref(1)
const { data } = await useFetch(() => `/api/users?page=${page.value}`)
</script>
2.5 监听参数变化 #
vue
<script setup lang="ts">
const userId = ref(1)
const { data, refresh } = await useFetch(() => `/api/users/${userId.value}`, {
watch: [userId]
})
</script>
三、useAsyncData #
3.1 基本用法 #
vue
<script setup lang="ts">
const { data, pending, error, refresh } = await useAsyncData(
'users',
() => $fetch('/api/users')
)
</script>
3.2 唯一键 #
vue
<script setup lang="ts">
const route = useRoute()
const { data } = await useAsyncData(
`article-${route.params.id}`,
() => $fetch(`/api/articles/${route.params.id}`)
)
</script>
3.3 多个数据源 #
vue
<script setup lang="ts">
const { data } = await useAsyncData(
'dashboard',
async () => {
const [users, posts, comments] = await Promise.all([
$fetch('/api/users'),
$fetch('/api/posts'),
$fetch('/api/comments')
])
return { users, posts, comments }
}
)
</script>
四、$fetch #
4.1 直接请求 #
vue
<script setup lang="ts">
const users = ref([])
const fetchUsers = async () => {
users.value = await $fetch('/api/users')
}
</script>
4.2 请求选项 #
vue
<script setup lang="ts">
const createUser = async () => {
const user = await $fetch('/api/users', {
method: 'POST',
body: {
name: '张三',
email: 'zhang@example.com'
}
})
}
</script>
4.3 错误处理 #
vue
<script setup lang="ts">
const fetchWithErrorHandling = async () => {
try {
const data = await $fetch('/api/users')
return data
} catch (error) {
console.error('请求失败:', error)
return null
}
}
</script>
五、懒加载 #
5.1 useLazyFetch #
vue
<script setup lang="ts">
const { data, pending } = await useLazyFetch('/api/users')
</script>
<template>
<div v-if="pending">
<SkeletonLoader />
</div>
<div v-else>
<UserList :users="data" />
</div>
</template>
5.2 useLazyAsyncData #
vue
<script setup lang="ts">
const { data, pending } = await useLazyAsyncData(
'users',
() => $fetch('/api/users')
)
</script>
六、请求配置 #
6.1 基础URL #
nuxt.config.ts:
typescript
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
}
}
})
使用:
vue
<script setup lang="ts">
const config = useRuntimeConfig()
const { data } = await useFetch('/users', {
baseURL: config.public.apiBase
})
</script>
6.2 请求头 #
vue
<script setup lang="ts">
const headers = {
'Authorization': 'Bearer token',
'Content-Type': 'application/json'
}
const { data } = await useFetch('/api/users', { headers })
</script>
6.3 超时设置 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
timeout: 5000
})
</script>
6.4 重试机制 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
retry: 3,
retryDelay: 1000
})
</script>
七、数据转换 #
7.1 transform选项 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
transform: (response) => {
return response.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`
}))
}
})
</script>
7.2 pick选项 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
pick: ['id', 'name', 'email']
})
</script>
7.3 默认值 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
default: () => []
})
</script>
八、缓存控制 #
8.1 缓存键 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
key: 'users-list'
})
</script>
8.2 缓存时间 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
getCachedData: (key) => {
const cached = useNuxtData(key)
if (cached.data.value && Date.now() - cached.timestamp < 60000) {
return cached.data.value
}
return null
}
})
</script>
8.3 禁用缓存 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
cache: 'no-cache'
})
</script>
九、服务端vs客户端 #
9.1 仅服务端 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/internal', {
server: true,
lazy: true
})
</script>
9.2 仅客户端 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/client-only', {
server: false
})
</script>
9.3 条件请求 #
vue
<script setup lang="ts">
const { data } = await useFetch('/api/users', {
server: import.meta.server,
client: import.meta.client
})
</script>
十、完整示例 #
10.1 分页列表 #
vue
<script setup lang="ts">
interface User {
id: number
name: string
email: string
}
interface PaginationResponse {
data: User[]
total: number
page: number
pageSize: number
}
const page = ref(1)
const pageSize = ref(10)
const { data, pending, refresh } = await useFetch<PaginationResponse>('/api/users', {
query: {
page,
pageSize
},
watch: [page, pageSize]
})
const totalPages = computed(() =>
Math.ceil((data.value?.total || 0) / pageSize.value)
)
const goToPage = (newPage: number) => {
page.value = newPage
}
</script>
<template>
<div>
<div v-if="pending">加载中...</div>
<div v-else>
<ul>
<li v-for="user in data?.data" :key="user.id">
{{ user.name }} - {{ user.email }}
</li>
</ul>
<div class="pagination">
<button
:disabled="page === 1"
@click="goToPage(page - 1)"
>
上一页
</button>
<span>{{ page }} / {{ totalPages }}</span>
<button
:disabled="page >= totalPages"
@click="goToPage(page + 1)"
>
下一页
</button>
</div>
<button @click="refresh">刷新</button>
</div>
</div>
</template>
10.2 搜索功能 #
vue
<script setup lang="ts">
const searchQuery = ref('')
const debouncedQuery = refDebounced(searchQuery, 300)
const { data, pending } = await useFetch('/api/search', {
query: {
q: debouncedQuery
},
watch: [debouncedQuery],
immediate: false
})
</script>
<template>
<div>
<input
v-model="searchQuery"
placeholder="搜索..."
/>
<div v-if="pending">搜索中...</div>
<div v-else-if="data?.length">
<div v-for="item in data" :key="item.id">
{{ item.title }}
</div>
</div>
<div v-else-if="searchQuery && !pending">
未找到结果
</div>
</div>
</template>
十一、总结 #
本章介绍了 Nuxt.js 数据获取基础:
useFetch简化数据获取useAsyncData灵活的数据获取$fetch直接请求- 懒加载数据获取
- 请求配置和选项
- 数据转换和缓存控制
数据获取是应用开发的核心,下一章我们将深入学习 useFetch 和 useAsyncData。
最后更新:2026-03-28