layouts
Nuxt 提供了一个布局框架,用于将通用的 UI 模式提取为可复用的布局。
为了获得最佳性能,放置在此目录中的组件在被使用时,会通过异步导入自动加载。
启用布局
通过在你的 app.vue 中添加 <NuxtLayout> 来启用布局:
app/app.vue
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
要使用某个布局:
- 在你的页面中通过 definePageMeta 设置
layout属性。 - 设置
<NuxtLayout>的name属性。 - 在路由规则中设置
appLayout属性。
布局名称会被规范化为 kebab-case(短横线命名),因此
someLayout 会变成 some-layout。如果未指定布局,则会使用
app/layouts/default.vue。如果你的应用中只有一个布局,我们建议使用 app.vue 来代替。
与其他组件不同,你的布局必须只有一个根元素,以便 Nuxt 能在布局切换之间应用过渡动画——并且这个根元素不能是 <slot />。
默认布局
添加一个 ~/layouts/default.vue:
app/layouts/default.vue
<template>
<div>
<p>所有页面共享的默认布局内容</p>
<slot />
</div>
</template>
在布局文件中,页面的内容会显示在 <slot /> 组件中。
具名布局
Directory Structure
-| layouts/
---| default.vue
---| custom.vue
然后你可以在页面中使用 custom 布局:
pages/about.vue
<script setup lang="ts">
declare module 'nuxt/app' {
interface NuxtLayouts {
'custom': unknown
}
}
// ---cut---
definePageMeta({
layout: 'custom',
})
</script>
了解更多关于 definePageMeta 的内容。
你也可以直接使用 <NuxtLayout> 的 name 属性覆盖所有页面的默认布局:
app/app.vue
<script setup lang="ts">
// 你可能会基于 API 调用或登录状态来选择它
const layout = 'custom'
</script>
<template>
<NuxtLayout :name="layout">
<NuxtPage />
</NuxtLayout>
</template>
如果你的布局位于嵌套目录中,布局的名称将基于它自身的路径目录和文件名,并去掉重复的部分。
| 文件 | 布局名称 |
|---|---|
~/layouts/desktop/default.vue | desktop-default |
~/layouts/desktop-base/base.vue | desktop-base |
~/layouts/desktop/index.vue | desktop |
为了清晰起见,我们建议布局的文件名与其名称保持一致:
| 文件 | 布局名称 |
|---|---|
~/layouts/desktop/DesktopDefault.vue | desktop-default |
~/layouts/desktop-base/DesktopBase.vue | desktop-base |
~/layouts/desktop/Desktop.vue | desktop |
动态切换布局
你也可以使用 setPageLayout 辅助函数来动态切换布局:
app/pages/index.vue
<script setup lang="ts">
declare module 'nuxt/app' {
interface NuxtLayouts {
'custom': unknown
}
}
// ---cut---
function enableCustomLayout () {
setPageLayout('custom')
}
definePageMeta({
layout: false,
})
</script>
<template>
<div>
<button @click="enableCustomLayout">
更新布局
</button>
</div>
</template>
你也可以使用路由规则中的 appLayout 属性为特定路由设置布局 v4.3:
nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 为特定路由设置布局
'/admin': { appLayout: 'admin' },
// 为多个路由设置布局
'/dashboard/**': { appLayout: 'dashboard' },
// 为某个路由禁用布局
'/landing': { appLayout: false },
},
})
当你想要在配置中集中管理布局,而不是在每个页面文件中管理,或者需要将布局应用到没有对应页面组件的路由(例如可能匹配很多路径的全捕获页面)时,这会很有用。
向布局传递 Props +4.4
你可以通过多种方式向布局传递 props。
通过 definePageMeta
使用 layout 属性的对象语法,直接从你的页面传递 props:
<script setup lang="ts">
definePageMeta({
layout: {
name: 'panel',
props: {
sidebar: true,
title: 'Dashboard',
},
},
})
</script>
<script setup lang="ts">
const props = defineProps<{
sidebar?: boolean
title?: string
}>()
</script>
<template>
<div>
<aside v-if="sidebar">
Sidebar
</aside>
<main>
<h1>{{ title }}</h1>
<slot />
</main>
</div>
</template>
Props 会基于你布局的
defineProps 进行完整的类型检查。你将在编辑器中获得自动补全和类型检查。通过 setPageLayout
你也可以在通过 setPageLayout 动态切换布局时传递 props:
setPageLayout('panel', { sidebar: true, title: 'Dashboard' })
在页面级别覆盖布局
如果你使用了页面,可以通过设置 layout: false,然后在页面内部使用 <NuxtLayout> 组件来完全掌控:
<script setup lang="ts">
definePageMeta({
layout: false,
})
</script>
<template>
<div>
<NuxtLayout name="custom">
<template #header>
一些头部模板内容。
</template>
页面的其余部分
</NuxtLayout>
</div>
</template>
<template>
<div>
<header>
<slot name="header">
默认头部内容
</slot>
</header>
<main>
<slot />
</main>
</div>
</template>
如果你在页面中使用 <NuxtLayout>,请确保它不是根元素(或者禁用布局/页面过渡)。