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>

&lt;NuxtLayout&gt; 会根据当前页面的 layout 元数据,选择对应的布局组件包裹 &lt;NuxtPage&gt;

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>

关键:布局必须包含 &lt;slot /&gt;——页面组件的内容会渲染在 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(&#123; layout: 'xxx' &#125;) 指定
  • 禁用布局layout: false,适用于全屏页面
  • 动态切换&lt;NuxtLayout :name="computed"&gt; 或运行时修改 layout ref
  • 布局过渡layoutTransition 配置 CSS 动画
  • 嵌套模拟:通过组件组合实现子布局效果
  • 实战:default(公共)+ auth(登录)+ studio(工作台)+ admin(后台)+ empty(全屏)

下一章讲全局组件与跨层级通信。