You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nuxt.js前端异步请求问题:如何先渲染内容再执行请求?

嘿,我刚接触Nuxt的时候也跟你一样纠结这个点!别慌,咱们有好几种办法能实现你想要的效果——先把页面的基础内容或者骨架渲染出来,再异步加载数据,完全就像Vue里用created钩子的感觉。

方法1:直接用Vue的created/mounted生命周期钩子

这是最贴近你熟悉的Vue写法的方式,页面会优先渲染组件的基础结构,等异步请求完成后再更新数据。举个实际例子:

<template>
  <div class="page-container">
    <!-- 先渲染的加载提示/骨架屏 -->
    <div class="loading-state" v-if="!article">
      <p>正在加载文章...</p>
      <!-- 你也可以换成更友好的骨架屏,后面会讲 -->
    </div>
    <!-- 数据加载完成后显示的真实内容 -->
    <article v-else>
      <h1>{{ article.title }}</h1>
      <div class="article-content" v-html="article.content"></div>
    </article>
  </div>
</template>

<script>
export default {
  data() {
    return {
      article: null // 初始化为null,用来判断加载状态
    }
  },
  async created() {
    // 这里发起异步请求,和Vue里的写法一模一样
    const res = await this.$axios.get('/api/articles/1')
    this.article = res.data
  }
}
</script>

这样页面会先快速渲染出来,显示“正在加载文章...”,等请求拿到数据后,自动替换成真实的文章内容,完全不会阻塞页面初始渲染。

方法2:用Nuxt的fetch钩子(兼顾服务端渲染场景)

如果你需要在服务端也触发这个异步请求,但又不想像asyncData那样阻塞页面渲染,fetch钩子就很合适。它可以直接修改组件的data,而且页面不会等待请求完成才渲染:

<template>
  <div class="post-list">
    <div v-if="!posts">加载帖子列表中...</div>
    <ul v-else>
      <li v-for="post in posts" :key="post.id" class="post-item">
        <h3>{{ post.title }}</h3>
        <p>{{ post.excerpt }}</p>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      posts: null
    }
  },
  async fetch() {
    // 在fetch里可以直接用this来修改组件数据
    const res = await this.$axios.get('/api/posts')
    this.posts = res.data
  }
}
</script>

fetch会在服务端和客户端都执行,但页面渲染不会等它完成,用户依然能先看到加载状态,体验更流畅。

进阶小技巧:用骨架屏提升用户体验

比起干巴巴的文字提示,用骨架屏模拟页面的真实结构,会让用户感觉加载速度更快。你可以自己用CSS写一个简单的骨架:

<template>
  <div>
    <div v-if="!article" class="skeleton">
      <div class="skeleton-title"></div>
      <div class="skeleton-line"></div>
      <div class="skeleton-line"></div>
      <div class="skeleton-line short"></div>
    </div>
    <article v-else>
      <!-- 真实文章内容 -->
    </article>
  </div>
</template>

<style scoped>
.skeleton {
  padding: 1.5rem;
}
.skeleton-title {
  height: 2rem;
  width: 70%;
  background: #f0f0f0;
  border-radius: 4px;
  margin-bottom: 1rem;
  animation: pulse 1.2s infinite ease-in-out;
}
.skeleton-line {
  height: 0.8rem;
  width: 100%;
  background: #f0f0f0;
  border-radius: 4px;
  margin-bottom: 0.6rem;
  animation: pulse 1.2s infinite ease-in-out;
}
.skeleton-line.short {
  width: 60%;
}
@keyframes pulse {
  0% { opacity: 0.6; }
  50% { opacity: 1; }
  100% { opacity: 0.6; }
}
</style>

总结一下:如果只是客户端加载数据,用created或者mounted就完全够用;如果需要服务端也参与数据获取,就选fetch。两种方式都能实现“先渲染部分内容,再异步加载数据”的需求,和你熟悉的Vue写法逻辑一致。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:39:12