Nuxt 3 SSR页面即时渲染并异步填充API内容的最优方案
Nuxt 3 SSR 即时渲染布局与导航、延迟展示内容的实现方案
一、实现思路与步骤
要实现布局/导航栏即时渲染,同时内容区等待API请求完成后展示(pending时显示骨架屏),核心是拆分布局与页面内容的渲染逻辑:
分离全局布局与页面内容
将导航栏、页头等通用框架放在Nuxt的layouts/default.vue中,这部分属于与页面数据无关的全局结构,会在SSR阶段直接渲染输出,用户打开页面就能立刻看到完整的布局框架。页面内容区处理加载状态
在具体页面组件(比如pages/index.vue)中,通过useFetch或useAsyncData请求数据,利用返回的pending状态控制骨架屏和真实内容的切换:- 当
pending为true时,显示骨架屏占位 - 当
pending为false时,替换为真实API数据内容
- 当
代码示例
布局文件 layouts/default.vue
<template> <div class="app-container"> <!-- 导航栏:SSR直接渲染,无需等待API --> <header class="navbar"> <div class="logo">我的博客</div> <nav> <a href="/">首页</a> <a href="/archive">归档</a> <a href="/about">关于</a> </nav> </header> <!-- 页面内容插槽:加载状态在这里处理 --> <main class="page-wrapper"> <slot /> </main> </div> </template> <style scoped> .navbar { display: flex; justify-content: space-between; padding: 1rem 2rem; background: #2c3e50; color: white; } .navbar a { color: white; margin-left: 1.5rem; text-decoration: none; } .page-wrapper { max-width: 1200px; margin: 2rem auto; padding: 0 1rem; } </style>
页面文件 pages/index.vue
<template> <div class="home-page"> <!-- API请求pending时显示骨架屏 --> <div v-if="pending" class="skeleton-list"> <div class="skeleton-item" v-for="i in 3" :key="i"> <div class="skeleton-title"></div> <div class="skeleton-text"></div> </div> </div> <!-- 请求完成后展示真实内容 --> <div v-else class="post-list"> <article v-for="post in data" :key="post.id" class="post-card"> <h2>{{ post.title }}</h2> <p>{{ post.excerpt }}</p> <a :href="`/posts/${post.id}`">阅读全文</a> </article> </div> </div> </template> <script setup> // 发起API请求,可根据需求配置server选项 const { data, pending } = await useFetch('https://api.example.com/posts', { // 若不需要服务端预取数据(比如用户私有内容、非SEO页面),开启server: false // server: false }) </script> <style scoped> /* 骨架屏样式 */ .skeleton-list { gap: 1.5rem; display: flex; flex-direction: column; } .skeleton-item { padding: 1rem; background: #f5f5f5; border-radius: 8px; } .skeleton-title { height: 24px; width: 60%; background: #e0e0e0; border-radius: 4px; margin-bottom: 0.8rem; } .skeleton-text { height: 16px; width: 100%; background: #e0e0e0; border-radius: 4px; } /* 真实内容样式 */ .post-list { gap: 1.5rem; display: flex; flex-direction: column; } .post-card { padding: 1.5rem; border: 1px solid #eee; border-radius: 8px; } .post-card h2 { margin-top: 0; color: #2c3e50; } </style>
二、关于useFetch({server: false})是否为通用/最佳实践
这取决于你的业务场景:
适合用
server: false的场景- 页面内容是用户私有数据(比如个人中心、购物车),服务端无法提前预取
- 页面不需要SEO优化(爬虫不需要读取内容)
- 想减轻服务端负载,把请求压力转移到客户端
这种场景下,用server: false是合理的,搭配pending状态做骨架屏也是通用做法。
不适合用
server: false的场景- 页面需要SEO:如果开启
server: false,服务端不会预取数据,返回的HTML中内容区是空的,爬虫无法抓取到真实内容,影响SEO - 首屏性能要求高:服务端预取数据后直接返回渲染好的内容,用户不需要等待客户端发起请求,首屏加载体验更好
这种场景下,应该保持server: true(useFetch的默认值),服务端会提前请求数据并渲染真实内容,客户端仅在路由切换时会触发pending状态显示骨架屏。
- 页面需要SEO:如果开启
通用结论
pending状态判断加载状态的方式是通用且推荐的,无论请求在服务端还是客户端发起都适用server: false不是通用最佳实践,需要根据页面是否需要SEO、是否为用户私有数据来选择是否开启
内容的提问来源于stack exchange,提问作者Simon Fischer
相关产品推荐
相关产品推荐

