布局
约 544 字大约 2 分钟
2026-02-07
重要
- 布局用于复用页面的公共结构,统一头部、侧边栏、底部等 UI
- 默认布局文件名为
default.vue,未提供时等价于直接渲染页面内容,命名方式使用kebab-case
最佳实践
- 默认布局保持轻量,只做结构容器,避免放重逻辑
- 自定义
app/app.vue时必须包含<NuxtLayout>,否则布局不生效 - 布局中涉及浏览器 API 的逻辑放客户端组件或
ClientOnly - 布局内通用 UI 拆成组件,避免重复与巨型模板
- 布局名保持语义化:
default、admin、docs等
核心概念
布局(Layout)是包裹页面的外层容器,用于复用页面结构。页面内容通过 <slot /> 注入到布局内部,布局文件位于 app/layouts,文件名即布局名
app
layouts
default.vue 默认布局
admin.vue 管理后台布局
docs.vue 文档布局
NuxtLayout
NuxtLayout 负责根据页面指定的布局名渲染对应布局。若自定义了 app/app.vue,则必须显式包含它
app/app.vue
<template>
<!-- NuxtLayout 根据页面 meta.layout 渲染对应布局 -->
<NuxtLayout>
<!-- NuxtPage 渲染当前页面组件 -->
<NuxtPage />
</NuxtLayout>
</template>definePageMeta
在页面中通过 definePageMeta 指定布局
<script setup lang="ts">
definePageMeta({
layout: 'admin',
})
</script>setPageLayout
当布局需要根据运行时条件切换时,使用 setPageLayout():
<script setup lang="ts">
const route = useRoute()
watchEffect(() => {
// 根据 query 动态切换布局
const isPreview = route.query.preview === '1'
setPageLayout(isPreview ? 'docs' : 'default')
})
</script>ClientOnly
当布局里包含只依赖浏览器环境的组件(例如读取 window、使用第三方仅客户端 SDK)时,建议用 ClientOnly 包裹这部分内容,避免 SSR 报错或 hydration 不一致。
app/layouts/docs.vue
<template>
<div class="docs-layout">
<aside>
<ClientOnly fallback-tag="div" fallback="目录加载中...">
<!-- 依赖浏览器 API 的目录组件 -->
<DocsToc />
</ClientOnly>
</aside>
<main>
<slot />
</main>
</div>
</template>提示
只包裹“确实需要客户端”的局部区域,不要把整个布局都包进 ClientOnly,否则会丢失 SSR 带来的首屏收益。
禁用布局
某些页面(如登录页)不需要布局时设置 layout: false:
<script setup lang="ts">
definePageMeta({
layout: false,
})
</script>