条件渲染
ClientOnly
仅在客户端渲染内容,SSR 时显示 fallback 内容。
vue
<template>
<ClientOnly>
<!-- 仅客户端渲染 -->
<MapComponent />
<!-- SSR 时的 fallback -->
<template #fallback>
<div class="loading">加载地图中...</div>
</template>
</ClientOnly>
</template>Props
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
hydrate | boolean | true | 是否参与 Hydration |
适用场景
| 场景 | 示例 |
|---|---|
使用 window、document 的组件 | 地图、图表库 |
| 第三方库不支持 SSR | 某些 jQuery 插件 |
| 避免 Hydration 不匹配 | 动态生成的 DOM |
完整示例:集成地图组件
vue
<template>
<div class="map-container">
<ClientOnly>
<LeafletMap :center="center" :zoom="12" />
<template #fallback>
<div class="map-placeholder">
<span class="spinner" />
<p>地图加载中...</p>
</div>
</template>
</ClientOnly>
</div>
</template>hydrate 属性
vue
<template>
<!-- 不参与 Hydration(纯客户端渲染,不比较 SSR 输出) -->
<ClientOnly :hydrate="false">
<BrowserAnimation />
</ClientOnly>
</template>INFO
️ 使用 <ClientOnly> 会导致内容不被搜索引擎抓取 对于 SEO 重要的内容,应避免包裹在此组件中
DevOnly
仅在开发环境渲染内容,生产构建时完全移除(零代码体积)。
vue
<template>
<DevOnly>
<DebugPanel />
<PerformanceMonitor />
</DevOnly>
</template>适用场景
| 场景 | 说明 |
|---|---|
| 调试面板 | 开发时显示组件状态 |
| 性能监控 | 开发时显示渲染时间 |
| 模拟数据 | 开发时使用假数据 |
| 开发辅助工具 | 仅开发环境需要的 UI |
完整示例:调试信息面板
vue
<template>
<div>
<h1>用户列表</h1>
<UserList :users="users" />
<!-- 仅开发环境显示 -->
<DevOnly>
<div class="debug-panel">
<p>API 响应时间: {{ responseTime }}ms</p>
<p>用户数量: {{ users.length }}</p>
<pre>{{ JSON.stringify(users[0], null, 2) }}</pre>
</div>
</DevOnly>
</div>
</template>TIP
<DevOnly> 在生产构建中会被 Tree-shaking 完全移除 不会有任何性能开销。比 v-if="import.meta.dev" 更优雅
NuxtIsland
服务端组件,仅在服务端渲染为纯 HTML,客户端不 Hydration(无 JS 发送到浏览器)。
vue
<template>
<!-- 渲染为纯 HTML,无 JS -->
<NuxtIsland name="Counter" :props="{ initial: 0 }" />
</template>创建服务端组件
在 components/ 下创建 .server.vue 文件:
vue
<!-- app/components/Counter.server.vue -->
<script setup lang="ts">
const props = defineProps<{ initial: number }>()
const count = ref(props.initial)
</script>
<template>
<div>Count: {{ count }}</div>
</template>Props
| Prop | 类型 | 说明 |
|---|---|---|
name | string | 服务端组件名称 |
props | object | 传递给组件的 Props |
服务端组件 vs 普通组件
| 特性 | 服务端组件 (.server.vue) | 普通组件 (.vue) |
|---|---|---|
| 渲染位置 | 仅服务端 | 服务端 + 客户端 |
| Hydration | ❌ 不参与 | ✅ 参与 |
| JS 体积 | 0 bytes | 包含组件逻辑 |
| 交互性 | ❌ 无交互 | ✅ 可交互 |
| 响应式 | ❌ 无响应式 | ✅ 响应式 |
| 适用场景 | 纯展示、静态内容 | 需要交互的组件 |
实际应用:纯展示型博客摘要
vue
<!-- app/components/BlogSummary.server.vue -->
<script setup lang="ts">
const props = defineProps<{ postId: number }>()
// 可以在服务端直接查询数据库
const post = await queryPost(props.postId)
</script>
<template>
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.excerpt }}</p>
<time>{{ post.date }}</time>
</article>
</template>vue
<!-- 在页面中使用 -->
<template>
<div>
<NuxtIsland name="BlogSummary" :props="{ postId: 1 }" />
<NuxtIsland name="BlogSummary" :props="{ postId: 2 }" />
</div>
</template>INFO
️ 服务端组件不支持交互(无 JS) 适合纯展示内容。如果需要交互,请使用普通组件或配合 <ClientOnly>