Nuxt.js数据获取基础 #

一、数据获取概述 #

Nuxt.js 提供了强大的数据获取能力,支持服务端渲染(SSR)和客户端渲染(CSR)场景。主要使用 useFetchuseAsyncData 组合式函数。

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 直接请求
  • 懒加载数据获取
  • 请求配置和选项
  • 数据转换和缓存控制

数据获取是应用开发的核心,下一章我们将深入学习 useFetchuseAsyncData

最后更新:2026-03-28