點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Layout 定義每頁固定部分

Sam Xiao's Avatar 2021-08-22

若想定義 Page 或 Template 的架構,如 Header、Footer、Sidebar…,可使用 Layout 定義之。

Version

Gridsome 0.7.23

Page

layout000

想建立獨立 page。

pages/Product.vue

<template>
  <div>
    <h1>Product</h1>
  </div>
</template>

pages 目錄下新增 Product.vue,會自動成為 product page。

Layout

layout001

在 page 加上 header。

pages/Product.vue

<template>
  <Layout>
    <h1>Product</h1>  
  </Layout>   
</template>

<h1> 外加上 <Layout>,會自動套用 Layout layout,product page 馬上有 header 了。

但為什麼 Product.vue 不用 import layout component 就直接能使用呢 ?

Global Layout

layouts/Default.vue

<template>
  <div class="layout">
    <header class="header">
      <strong>
        <g-link to="/">{{ $static.metadata.siteName }}</g-link>
      </strong>
      <nav class="nav">
        <g-link class="nav__link" to="/">Home</g-link>
        <g-link class="nav__link" to="/about/">About</g-link>
      </nav>
    </header>
    <slot/>
  </div>
</template>

<static-query>
query {
  metadata {
    siteName
  }
}
</static-query>

<style>
body {
  font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  margin:0;
  padding:0;
  line-height: 1.5;
}

.layout {
  max-width: 760px;
  margin: 0 auto;
  padding-left: 20px;
  padding-right: 20px;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  height: 80px;
}

.nav__link {
  margin-left: 20px;
}
</style>

Gridsome 在 layouts 目錄下放了 Default.vue,其本質是使用 slot 的 component,將由 page 或 template 提供 slot 內容。

Main

main.js

import DefaultLayout from '~/layouts/Default.vue'

export default function (Vue, { router, head, isClient }) {
  Vue.component('Layout', DefaultLayout)
}

Layout 通常會在 src/main.js 使用 Vue.component 註冊成 global component,因此每個 page 能直接使用。

Local Layout

pages/Product.vue

<template lang='pug'>
  <MyLayout>
    <h1>Product</h1>
  </MyLayout>
</template>

<script>
import MyLayout from '~/layouts/Default'

export default {
  components: {
    MyLayout
  }
}
</script>

第 8 行

import MyLayout from '~/layouts/Default'

Default.vue 引用成 MyLayout component。

11 行

components: {
  MyLayout
}

components 下宣告 Layout component。

由於 layout 本質就是 component,若你不想在 main.js 註冊成 global component,也可在每個 page 中單獨 import layout 使用。

Conclusion

  • Layout 適合建立每夜固定部分給 page 或 template 使用,其本質就是使用 slot 的 global component,只是 Gridsome 另外提出 layout 概念

Reference

Reed Barger, Layouts, Aliasing
Gridsome, Layouts