Nuxt 3 学习笔记(七) Nuxt 3 布局模板 (Layouts)

3,618 阅读6分钟

前言

Nuxt 3 提供了一个布局模板 (Layouts) 的功能,可以让你定义好布局模板后,在整个 Nuxt 中使用,举例来说就很适合如上方有导航栏,下方是网页主体内容的这种排版方式,将其构建成一个布局模板后,我们就可以重复使用这种布局方式。

布局模板 (Layouts)

布局模板通常放置在 ./layouts 目录之下,也具有异步自动导入的效果,当新增好布局文件后,我们就可以在 app.vue 中,添加 <NuxtLayout /> 组件来表示使用布局模板,也可以通过 name 设定不同的模板名称。

建立一个预设的布局模板

布局模板在 Nuxt 3 中有约定一个名称为 default.vue 作为预设的模板,如果在页面组件中未特别指定要使用哪个模板或 <NuxtLayout /> 没有设定 name 属性,那么都将会使用 default 作为预设的布局。

Step 1. 建立预设布局模板

新增 ./layouts/default.vue 文件内容如下:

<template>
  <div class="bg-sky-100 py-2">
    <p class="px-6 py-4 text-2xl text-gray-700">这是预设的布局,全部页面都会使用到</p>
    <slot />
  </div>
</template>

在布局模板中,通常会包含一个 <slot /> 插槽,这个未命名的插槽 (slot) 即为预设插槽,这将会是采用这个布局模板的页面组件,显示的内容容器位置。

Step 2. 添加 组件

调整 app.vue 文件,内容如下,我们添加 <NuxtLayout> 作为布局模板显示的位置,name 属性预设是 default,不过我们还是写上 name="default" 避免误会,这个 name 属性值对应的即是布局模板的名称。

布局模板呈现

下图可以看见,我们在 app.vue 所写的文字「这里是最外层 app.vue」,会是在最外层,而紧接着的 <NuxtLayout name="default"></NuxtLayout>,就是布局页面 default.vue

image.png

布局模板中的插槽

如果你有注意到,default.vue 文件内代码内,有一个插槽 <slot />,这里就会是 <NuxtLayout> 内的元素所显示的位置。 例如,我们在 app.vue 稍作调整:

<template>
  <div class="m-4 bg-white">
    <p class="pb-4 text-2xl text-slate-600">这里是最外层 app.vue</p>
    <NuxtLayout name="default">
      <p class="px-6 pt-4 text-xl text-slate-800">
        被 NuxtLayout 包裹的组件将会放置到 Layout 的 slot 中
      </p>
    </NuxtLayout>
  </div>
</template>

被 <NuxtLayout name="default"> 包裹的元素,就会在布局模板中的插槽 <slot /> 显示。

image.png

在布局模板中建立多个插槽

当然,你也可以在布局模板中添加多个插槽,并给予名称,这样就可以将内容安排到特定的位置。

Step 1. 建立两个具名的插槽 (Slot),分别为 header 与 footer

如果插槽没有给予 name 属性,预设为 default./layouts/default.vue 文件内容如下:

<template>
  <div class="bg-sky-100 py-2">
    <p class="px-6 py-4 text-2xl text-gray-700">这是预设的布局,全部页面都会使用到</p>
    <slot name="header" />
    <slot />
    <slot name="footer" />
  </div>
</template>

Step 2. 将不同内容,显示于指定的插槽位置。

app.vue,内容如下:

<template>
  <div class="m-4 bg-white">
    <p class="pb-4 text-2xl text-slate-600">这里是最外层 app.vue</p>
    <NuxtLayout name="default">
      <template #header>
        <p class="px-6 pt-4 text-xl text-green-500">这段会放置在 header 插槽</p>
      </template>
      <template #default>
        <p class="px-6 pt-4 text-xl text-cyan-500">
          被 NuxtLayout 包裹的组件将会放置到 Layout 的预设 slot 中
        </p>
      </template>
      <template #footer>
        <p class="px-6 pt-4 text-xl text-blue-500">这段会放置在 footer 插槽</p>
      </template>
    </NuxtLayout>
  </div>
</template>

布局模板呈现

下图可以看见,我们就可以依此来安排各个组件,于布局模板插槽的所在位置。 image.png

布局模板与路由页面

当你熟悉了插槽配置,你也可以在其中添加 <NuxtPage /> 与建立 pages 下的页面组件,以达到不同的路由页面,使用相同的布局方式。

如果布局模板结合了路由页面,整体网站就会如下的巢状显示方式,网站的入口点 app.vue 放置布局模板,模板内的内容则使用路由的 <NuxtPage />,最后各个路由的页面就会在 <NuxtPage /> 容器中显示。

+---------------------------+
| app.vue                   |
| +-----------------------+ |
| | layout                | |
| | +-------------------+ | |
| | | page              | | |
| | |                   | | |
| | |                   | | |
| | +-------------------+ | |
| +-----------------------+ |
+---------------------------+

建立布局模板与路由页面

Step 1. 调整 app.vue 入口点

将 app.vue 调整为以下内容:

<template>
  <div class="m-4 bg-white">
    <p class="pb-4 text-2xl text-slate-600">这里是最外层 app.vue</p>
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </div>
</template>

Step 2. 建立路由页面

建立 ./pages/index.vue,内容如下:

<template>
  <div class="m-6 bg-slate-50 py-24">
    <div class="flex flex-col items-center">
      <h1 class="text-6xl font-semibold text-sky-400">2023 Juejin</h1>
      <p class="mt-4 text-9xl font-bold text-gray-600">nuxt3</p>
    </div>
  </div>
</template>

多个路由页面共用预设布局模板

承上,我们建立好预设的布局模板,让它负责显示路由的页面。

Step 1. 新增路由页面

新增 ./pages/about.vue,内容如下:

<template>
  <div class="mx-6 mb-4 bg-slate-50 py-24">
    <div class="flex flex-col items-center">
      <h1 class="text-6xl font-semibold text-yellow-400">大家好!我是 Potato</h1>
      <p class="my-8 text-3xl text-gray-600">这里是 /about</p>
    </div>
  </div>
</template>

新增 ./pages/contact.vue,内容如下:

<template>
  <div class="mx-6 mb-4 bg-slate-50 py-24">
    <div class="flex flex-col items-center">
      <h1 class="text-6xl font-semibold text-rose-400">如果没事不要找我 xDDD</h1>
      <p class="my-8 text-3xl text-gray-600">这里是 /contact</p>
    </div>
  </div>
</template>

Step 2. 新增路由连结

调整 ./pages/index.vue,内容如下:

<template>
  <div class="mx-6 mb-4 bg-white py-24">
    <div class="flex flex-col items-center">
      <h1 class="text-6xl font-semibold text-gray-800">这里是首页</h1>
      <div class="my-4 flex space-x-4">
        <NuxtLink to="/about">前往 About</NuxtLink>
        <NuxtLink to="/contact">前往 Contact</NuxtLink>
      </div>
    </div>
  </div>
</template>

建立多个布局模板

你也可以建立多个布局模板,再依据不同的情境,使用不同的布局模板。

使用指定的布局模板

Step 1. 建立新的布局模板

新增 ./layouts/custom.vue,内容如下:

<template>
  <div class="bg-rose-100 py-2">
    <p class="px-6 py-4 text-2xl text-gray-700">
      使用 <span class="font-bold text-rose-500">Custom</span> 布局
    </p>
    <slot />
  </div>
</template>

Step 2. 新增一个路由页面

新增 ./pages/custom.vue,内容如下:

<template>
  <div class="m-6 bg-slate-50 py-24">
    <div class="flex flex-col items-center">
      <h1 class="text-6xl font-semibold text-sky-400">2023 Juejin</h1>
      <p class="mt-4 text-9xl font-bold text-gray-600">nuxt3</p>
    </div>
  </div>
</template>

Step 3. 使用指定布局模板

在 ./pages/custom.vue 中的 script 使用 definePageMeta 方法:

<script setup>
definePageMeta({
  layout: 'custom'
})
</script>

布局模板与路由页面的呈现

definePageMeta 方法,提供我们可以设定特定的布局模板,layout 参数值所对应的名称,即为 ./layouts 目录下的布局模板。

注意,布局模板的命名被规范使用 Kebab Case 命名法,若文件名称为 customLayout.vue,它将会以 custom-layout 作为 name 属性传递给

更进阶的指定布局模板

我们能使用 layout: false 来禁止使用预设的布局模板,并在 template 添加 <NuxtLayout name="custom"> 来使用 custom 布局模板。

<template>
  <NuxtLayout name="custom">
    <div class="mx-6 mb-4 bg-white py-24">
      <div class="flex flex-col items-center">
        <h1 class="text-6xl font-semibold text-sky-400">2023 Juejin</h1>
        <p class="mt-4 text-9xl font-bold text-gray-600">nuxt3</p>
      </div>
    </div>
  </NuxtLayout>
</template>

<script step>
definePageMeta({
  layout: false
})
</script>

当布局模板可以在 template 中设定使用,我们就能结合插槽甚至动态的调整 name 属性,做出更多样灵活的布局效果。

上图的参考代码:
./layouts/custom.vue

<template>
  <div class="bg-rose-100 py-2">
    <p class="px-6 py-4 text-2xl text-gray-700">
      使用 <span class="font-bold text-rose-500">Custom</span> 布局
    </p>
    <slot />
    <slot name="footer" />
  </div>
</template>

./pages/custom.vue

<template>
  <NuxtLayout name="custom">
    <template #default>
      <div class="mx-6 mb-4 bg-white py-24">
        <div class="flex flex-col items-center">
          <h1 class="text-6xl font-semibold text-sky-400">2023 Junjin</h1>
          <p class="mt-4 text-9xl font-bold text-gray-600">nuxt3</p>
        </div>
      </div>
    </template>
    <template #footer>
      <div class="flex flex-col items-center">
        <p class="mt-4 text-xl text-slate-600">感谢您阅读 Nuxe 3 学习笔记~</p>
      </div>
    </template>
  </NuxtLayout>
</template>

<script step>
definePageMeta({
  layout: false
})
</script>

当你使用 definePageMeta 方法,禁止使用预设的布局模板后,你也能使用 setPageLayout 方法来动态改变布局。 例如:

<script setup>
const = enableCustomLayout () => {
  setPageLayout('custom')
}
</script>

实战练习

我们将这篇所介绍的布局模板与路由页面的配置方式与特性熟悉之后,我们就来做一个小练习。

使用预设布局模板,使得每一个路由页面都能有 Header,点击「Nuxt 3 学习笔记」随时可以回至首页,并将其中一个页面禁止使用预设布局,改采用自订的布局模板。

实战练习参考代码

小结

当你看过了这篇内容后,你会发现 Nuxt 3 所提供的布局模板非常的好用,布局模板规划好后,尔后页面所使用到的相同布局,只需要更改同一个布局模板,如果再结合组件化技巧,更是让你的代码兼具重复使用性与维护性。


感谢大家的阅读,也欢迎大家给予建议 :) 如果对这个 Nuxt 3 系列感兴趣,可以关注一下小编,也欢迎分享给喜欢或正在学习 Nuxt 3 的伙伴。

范例代码

参考资料