Layouts 布局系统
大多数页面都有共同的结构——顶部导航栏、侧边栏、底部版权信息。如果每个页面都重复写这些代码,维护成本极高。Nuxt4 的 Layouts 系统让你定义可复用的页面框架,页面只需关注自己独特的内容区域。本章从默认布局讲到动态切换、嵌套布局,最终实现 AI 视频平台的多套布局管理。
1. default.vue 与自定义 Layout
1.1 布局的基本结构
app/
├── layouts/
│ ├── default.vue ← 默认布局(不指定 layout 时使用)
│ ├── auth.vue ← 登录/注册页专用布局
│ ├── studio.vue ← 创作工作台布局
│ └── admin.vue ← 管理后台布局
├── pages/
│ ├── index.vue ← 使用 default 布局
│ ├── login.vue ← 使用 auth 布局
│ └── studio/
│ └── index.vue ← 使用 studio 布局
└── app.vue
1.2 app.vue 中启用布局
<!-- app/app.vue -->
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template><NuxtLayout> 会根据当前页面的 layout 元数据,选择对应的布局组件包裹 <NuxtPage>。
1.3 默认布局
<!-- app/layouts/default.vue -->
<template>
<div class="min-h-screen flex flex-col">
<AppHeader />
<main class="flex-1">
<slot /> <!-- 页面内容插入这里 -->
</main>
<AppFooter />
</div>
</template>关键:布局必须包含 <slot />——页面组件的内容会渲染在 slot 位置。
1.4 自定义布局
<!-- app/layouts/auth.vue — 登录页布局(无导航栏、居中卡片) -->
<template>
<div class="min-h-screen flex items-center justify-center bg-gray-50">
<div class="w-full max-w-md">
<slot />
</div>
</div>
</template><!-- app/layouts/studio.vue — 工作台布局(侧边栏 + 主内容区) -->
<template>
<div class="min-h-screen flex">
<StudioSidebar class="w-64 shrink-0" />
<div class="flex-1 flex flex-col">
<StudioTopBar />
<main class="flex-1 p-6">
<slot />
</main>
</div>
</div>
</template>2. definePageMeta layout 动态切换
2.1 静态指定布局
<!-- app/pages/login.vue -->
<script setup lang="ts">
definePageMeta({
layout: 'auth', // 使用 auth 布局
})
</script>
<template>
<LoginForm />
</template><!-- app/pages/studio/index.vue -->
<script setup lang="ts">
definePageMeta({
layout: 'studio', // 使用 studio 布局
})
</script>
<template>
<StudioDashboard />
</template>2.2 禁用布局
<script setup lang="ts">
definePageMeta({
layout: false, // 不使用任何布局
})
</script>
<template>
<!-- 全屏页面,如视频播放全屏模式 -->
<FullScreenPlayer />
</template>2.3 动态切换布局
<script setup lang="ts">
const route = useRoute()
// 根据用户角色动态选择布局
const user = useAuth()
definePageMeta({
layout: false, // 先禁用默认布局
})
// 在 app.vue 中用 :name 动态指定
</script>在 app.vue 中实现动态布局:
<!-- app/app.vue -->
<template>
<NuxtLayout :name="currentLayout">
<NuxtPage />
</NuxtLayout>
</template>
<script setup lang="ts">
const route = useRoute()
const currentLayout = computed(() => {
// 根据路由路径选择布局
if (route.path.startsWith('/studio')) return 'studio'
if (route.path.startsWith('/admin')) return 'admin'
if (route.path.startsWith('/auth')) return 'auth'
return 'default'
})
</script>2.4 运行时切换布局
<script setup lang="ts">
const layout = ref('default')
function toggleFullscreen() {
layout.value = layout.value === 'default' ? false : 'default'
}
</script>
<template>
<NuxtLayout :name="layout">
<button @click="toggleFullscreen">切换全屏</button>
<NuxtPage />
</NuxtLayout>
</template>2.5 布局过渡动画
<!-- app/app.vue -->
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>// nuxt.config.ts
export default defineNuxtConfig({
app: {
layoutTransition: {
name: 'layout',
mode: 'out-in',
},
},
})/* app/assets/css/transitions.css */
.layout-enter-active,
.layout-leave-active {
transition: opacity 0.3s ease;
}
.layout-enter-from,
.layout-leave-to {
opacity: 0;
}3. 嵌套 Layout 实现
3.1 Nuxt 不支持原生嵌套布局
Nuxt 的 Layout 系统不支持布局嵌套——每个页面只能有一个布局。但可以通过组件组合来模拟:
3.2 使用组件组合模拟嵌套
<!-- app/layouts/studio.vue — 工作台主布局 -->
<template>
<div class="min-h-screen flex">
<StudioSidebar />
<div class="flex-1">
<StudioTopBar />
<slot />
</div>
</div>
</template><!-- app/components/studio/SubLayout.vue — 子布局组件 -->
<template>
<div class="flex h-full">
<nav class="w-48 border-r p-4">
<slot name="sidebar" />
</nav>
<main class="flex-1 p-6">
<slot />
</main>
</div>
</template><!-- app/pages/studio/settings.vue — 使用嵌套结构 -->
<script setup lang="ts">
definePageMeta({ layout: 'studio' })
</script>
<template>
<StudioSubLayout>
<template #sidebar>
<SettingsNav />
</template>
<!-- 主内容区 -->
<SettingsForm />
</StudioSubLayout>
</template>4. AI 视频平台多套布局管理
4.1 布局规划
app/layouts/
├── default.vue ← 公共页面:首页、视频列表、视频详情
├── auth.vue ← 登录注册:居中卡片,无导航
├── studio.vue ← 创作工作台:侧边栏 + 工具栏
├── admin.vue ← 管理后台:管理侧边栏 + 面包屑
└── empty.vue ← 空布局:全屏播放、嵌入页面
4.2 默认布局
<!-- app/layouts/default.vue -->
<template>
<div class="min-h-screen flex flex-col bg-white dark:bg-gray-950">
<AppHeader />
<main class="flex-1">
<slot />
</main>
<AppFooter />
</div>
</template>
<script setup lang="ts">
const route = useRoute()
// 视频详情页不显示 Footer
const showFooter = computed(() => !route.path.startsWith('/videos/'))
</script>4.3 工作台布局
<!-- app/layouts/studio.vue -->
<template>
<div class="min-h-screen flex bg-gray-50 dark:bg-gray-900">
<!-- 侧边栏 -->
<aside class="w-64 bg-white dark:bg-gray-800 border-r shrink-0">
<div class="p-4">
<NuxtLink to="/" class="text-xl font-bold">AI 视频</NuxtLink>
</div>
<StudioNav />
</aside>
<!-- 主内容区 -->
<div class="flex-1 flex flex-col min-w-0">
<header class="h-14 border-b bg-white dark:bg-gray-800 flex items-center px-6">
<StudioBreadcrumb />
<div class="ml-auto">
<UserMenu />
</div>
</header>
<main class="flex-1 overflow-auto p-6">
<slot />
</main>
</div>
</div>
</template>4.4 页面与布局的映射
<!-- app/pages/index.vue — 默认布局 -->
<template>
<HeroSection />
<FeaturedVideos />
</template>
<!-- app/pages/login.vue — auth 布局 -->
<script setup lang="ts">
definePageMeta({ layout: 'auth' })
</script>
<!-- app/pages/studio/index.vue — studio 布局 -->
<script setup lang="ts">
definePageMeta({ layout: 'studio', middleware: 'auth' })
</script>
<!-- app/pages/videos/[id]/fullscreen.vue — 无布局 -->
<script setup lang="ts">
definePageMeta({ layout: false })
</script>本章小结
- 默认布局:
layouts/default.vue,不指定 layout 时自动使用 - 自定义布局:
layouts/xxx.vue,通过definePageMeta({ layout: 'xxx' })指定 - 禁用布局:
layout: false,适用于全屏页面 - 动态切换:
<NuxtLayout :name="computed">或运行时修改layoutref - 布局过渡:
layoutTransition配置 CSS 动画 - 嵌套模拟:通过组件组合实现子布局效果
- 实战:default(公共)+ auth(登录)+ studio(工作台)+ admin(后台)+ empty(全屏)
下一章讲全局组件与跨层级通信。