VitePress 中如何正确使用 Vue 组件的异步数据获取?

Mr.正利 阅读 45

我在 VitePress 里写了一个简单的 Vue 组件,想在页面加载时从 API 拿点数据,但发现 onMounted 里请求的数据在 SSR 阶段不生效,页面首次渲染是空的,只有客户端激活后才显示。这体验太差了,有没有办法让 VitePress 在服务端就渲染出真实数据?

我试过把逻辑放到 setup 里直接执行,也试过用 onBeforeMount,但都没用。是不是 VitePress 不支持服务端获取数据?还是我姿势不对?

<script setup>
import { ref, onMounted } from 'vue'

const data = ref(null)

onMounted(async () => {
  const res = await fetch('/api/data')
  data.value = await res.json()
})
</script>

<template>
  <div>{{ data?.title || 'Loading...' }}</div>
</template>
我来解答 赞 13 收藏
二维码
手机扫码查看
2 条解答
诸葛文婷
VitePress 是支持服务端获取数据的,问题在于你用的 onMounted 只在客户端执行。

最简单的改法:把 onMounted 换成 onServerPrefetch

这个钩子在 SSR 阶段会执行,客户端也会等数据就绪后再渲染:

<script setup>
import { ref, onServerPrefetch } from 'vue'

const data = ref(null)

const loadData = async () => {
const res = await fetch('/api/data')
data.value = await res.json()
}

onServerPrefetch(loadData)
</script>

<template>
<div>{{ data?.title || 'Loading...' }}</div>
</template>


这样服务端渲染时就能拿到数据了,客户端激活前也不会显示 Loading。



如果你的数据比较通用,推荐用 VitePress 的 Data Loader 方式

.vitepress/theme 目录下创建 data.js

export default {
async load() {
const res = await fetch('/api/data')
return await res.json()
}
}


然后在组件里这样用:

<script setup>
import { useData } from 'vitepress'

const { theme } = useData()
// 访问时用 theme.value.data 或者直接在模板里用 $data
</script>

<template>
<div>{{ $data.title }}</div>
</template>


Data Loader 的好处是数据在构建时就获取了,生成的 HTML 直接包含数据,首屏加载更快,也不会有闪烁。

两种方案看你的场景选就行:组件级别的异步数据用 onServerPrefetch,全局共享的数据用 Data Loader。
点赞
2026-03-14 12:00
UI洛熙
UI洛熙 Lv1
onMounted 是客户端专用的钩子,服务端渲染时根本不会跑,当然拿不到数据。最简单的办法是用 Vue 的 onServerPrefetch,这玩意儿会在服务端渲染 HTML 前把数据请求完,保证首屏就有内容,不过你得自己在客户端加个兜底逻辑,防止 SPA 跳转的时候没数据。

<script setup>
import { ref, onServerPrefetch } from 'vue'

const data = ref(null)

const fetchData = async () => {
const res = await fetch('https://api.your-domain.com/api/data')
data.value = await res.json()
}

// 服务端渲染时执行
onServerPrefetch(fetchData)

// 客户端激活时如果没数据就再请求一次(SPA 跳转时需要)
if (!data.value) {
fetchData()
}
</script>

<template>
<div>{{ data?.title || 'Loading...' }}</div>
</template>
点赞 3
2026-03-04 18:39