親バカエンジニアのナレッジ帳

webのエンジニアをやっており、日頃の開発で詰まったことや書き残しておきたいことを載せています。

vue.jsで全ページ共通コンポーネントのまとめ方


コンポーネントでヘッダーやフッターなど、どのページでも共通となる部分をまとめることってありますよね。
Vue.jsではその時、どのようにまとめるのが良いのでしょうか。

全ページで毎回コンポーネントを書く方法

まずは全ページで毎回コンポーネントを書く方法です。
今回ページ構成はトップとPage1とPage2の2つがあるとします。


※ヘッダーのコンポーネントをshared-header、フッターのコンポーネントをshared-footerとしています。

<template>
  <div>
    <shared-header></shared-header>
    <div>
        // Topの処理内容
    </div>
    <shared-footer></shared-footer>
  </div>
</template>

Page1コンポーネント、Page2コンポーネント

<template>
  <div>
    <shared-header></shared-header>
    <div>
      // Page1またはPage2の処理内容
    </div>
    <shared-footer></shared-footer>
  </div>
</template>

例えばヘッダー、フッターに毎度引数を渡して処理する場合などはこの方法が無難かもしれませんね。
ただこの方法では、全ページに毎回毎回ヘッダー、フッターなどの共通コンポーネントを忘れずに記載する必要があり、実装漏れのリスクも発生します。
また、毎度コンポーネントをインポートするのも面倒ですね。



共通コンポーネントをrouterの外に出す方法

これがおすすめの方法です。
それぞれのページをrouterの階層で子コンポーネントにしてしまう方法です。
まずはIndex.vueを作り(名前は何でもいいですが)、その中で共通のコンポーネントを記載しておきます。
router-viewの中身が子コンポーネントの内容となり、子コンポーネント(各ページのコンポーネント)には、共通のコンポーネントの記載が不要となります。

具体的なコードです。

まずはrouter.jsです。

import Router from 'vue-router'
import Index from '@/pages/Index'
import Top from '@/pages/Top'
import Page1 from '@/pages/Page1'
import Page2 from '@/pages/Page2'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: Index,
      children: [
        {
          path: '',
          name: 'Top',
          component: Top
        },
        {
          path: 'page1',
          name: 'page1',
          component: Page1
        },
        {
          path: 'page2',
          name: 'page2',
          component: Page2
        }
      ]
    }
  ]
})

App.vueに関しては、元々の記述から変更する必要はありません。

<template>
  <router-view></router-view>
</template>

そしてIndex.vueです。
ここに共通となるコンポーネントを記載しておき、router-viewは子コンポーネントの内容となります。

<template>
  <div>
    <shared-header></shared-header>
    <router-view></router-view>
    <shared-footer></shared-footer>
  </div>
</template>

あとは各ページのコンポーネントを普通に書いて大丈夫です。共通コンポーネントの記載はIndex.vueに集約されているために、ヘッダーやフッターは反映されるようになります。

Topコンポーネント

<template>
    <div>
        // Topの処理内容
    </div>
</template>

Page1コンポーネント、Page2コンポーネント

<template>
    <div>
        // Page1またはPage2の処理内容
    </div>
</template>

欠点となるポイントとしては、Index.vueで共通コンポーネントやrouter-viewの外枠をdivなどで囲わなければいけなくなる点です。body直下にヘッダーやフッターを置きたい人にとっては余計なタグを入れなければいけなくなる点が気持ち悪いかもしれませんね。



おまけ 複数のデザイン構成のサイトを作る場合

蛇足となりますが、これを応用して複数の別なデザイン構成のサイトを作る時にも使えます。
例えばCMS機能を実装する時に、ユーザーが閲覧する画面に加えて管理画面を作りたい時などに使えます。
管理画面とユーザーが閲覧する画面は、当然ヘッダー要素やフッター要素などパーツが異なりますよね。
方法を簡単に言いますと、親コンポーネントを複数作るのです。

まずはrouterです

import Router from 'vue-router'
import IndexAdmin from '@/pages/IndexAdmin'
import TopAdmin from '@/pages/TopAdmin'
import PageAdmin1 from '@/pages/PageAdmin1'
import PageAdmin2 from '@/pages/PageAdmin2'
import Index from '@/pages/Index'
import Top from '@/pages/Top'
import Page1 from '@/pages/Page1'
import Page2 from '@/pages/Page2'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/admin',
      component: IndexAdmin,
      children: [
        {
          path: '',
          name: 'TopAdmin',
          component: TopAdmin
        },
        {
          path: 'pageAdmin1',
          name: 'pageAdmin1',
          component: PageAdmin1
        },
        {
          path: 'pageAdmin2',
          name: 'pageAdmin2',
          component: PageAdmin2
        }
      ]
    },
    {
      path: '/',
      component: Index,
      children: [
        {
          path: '',
          name: 'Top',
          component: Top
        },
        {
          path: 'page1',
          name: 'page1',
          component: Page1
        },
        {
          path: 'page2',
          name: 'page2',
          component: Page2
        }
      ]
    }
  ]
})

管理画面はpathに/adminを入れて、ドメイン/adminとURLに入力すれば管理画面のトップ(TopAdminコンポーネント)が表示されるようになります。
同様に/admin/pageAdmin1、/admin/pageAdmin2...と入力するとそれぞれのページが表示されます。

そしてIndex.vueとは別にIndexAdmin.vueを作成します。
※管理画面のヘッダー、フッターのコンポーネントをshared-admin-header、shared-admin-footerとします。

<template>
  <div>
    <shared-admin-header></shared-admin-header>
    <router-view></router-view>
    <shared-admin-footer></shared-admin-footer>
  </div>
</template>

このようにすれば、管理画面とユーザーの画面それぞれで独立して実装しやすくなりますね。


基礎から学ぶ Vue.js

基礎から学ぶ Vue.js

  • 作者:mio
  • 発売日: 2018/05/29
  • メディア: 単行本(ソフトカバー)
速習Vue.js 速習シリーズ

速習Vue.js 速習シリーズ

  • 作者:山田祥寛
  • 発売日: 2018/03/28
  • メディア: Kindle版
Vue.jsとFirebaseで作るミニWebサービス (技術書典シリーズ(NextPublishing))

Vue.jsとFirebaseで作るミニWebサービス (技術書典シリーズ(NextPublishing))

  • 作者:渡邊 達明
  • 発売日: 2018/07/13
  • メディア: オンデマンド (ペーパーバック)