vue-routerとコンポーネントファイルだけでページを量産する

こんにちはこんにちは、Vue.js 初心者です。
さて、Vue.jsは強力なコンテンツ処理を秘めたフレームワークだと勝手に思ってるんですが、ページ作るたびにvue-routerに定義書いて、ページ分のコンポーネントファイルを作って、ひいひいコーディングするのは非常にナンセンスというかWordPressでええやん感が出ますね。

で、そんなはずは無えだろボケと思いまして、vue-routerを使ったページ量産構造が作れたのでメモしておく。

```router/index.js
import Vue from 'vue';
import Router from 'vue-router';

// 普通のページ
import Top from '@/layouts/Top';

// 量産型ページ
import SinglePage from '@/layouts/SinglePage';
import SectionOne from '@/components/SectionOne';
import SectionTwo from '@/components/SectionTwo';
import PageNotFound from '@/components/PageNotFound';

Vue.use(Router);

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Top',
      component: Top,
    },
    {
      path: '*',
      component: SinglePage,
      children: [
        {
          path: '/sec1',
          component: SectionOne,
          meta: {
            title: 'うんこパラダイス',
            breadcrumbs: [
              {
                path: '/sec1',
                name: 'うんこパラダイス',
              },
            ],
          },
        },
        {
          path: '/sec2',
          component: SectionTwo,
          meta: {
            title: 'ちんちんぶらぶら',
            breadcrumbs: [
              {
                path: '/hoge',
                name: 'ほげ',
              },
              {
                path: '/sec2',
                name: 'ちんちんぶらぶら',
              },
            ],
          },
        },
        {
          // ちなみにこれステータスが２００になるから注意な
          path: '*', // 見つかりません的な
          component: PageNotFound,
        },
      ],
    },
  ],
});
```

見ての通り、`path`を入れ子にしている。`@/layouts/SinglePage.vue`ファイルを親として、パスをワイルドカードで指定、その`children`たちとして`path`に合致する状態を作り出す。合致したら、そこで定義している`component`（単数形なことに注意）が参照されて、`<router-view>`を通して内容が置き換わる。

重要なのは`meta`フィールドで、ここの定義でもってページタイトルと、パンくずリストを構成させる。`meta.breadcrumbs`で定義した配列とオブジェクトの数でもってパンくずリストを生成させたいのだ。

さて、量産型ページを司る親コンポーネントファイル（ここでは、レイアウトと称する）の設定をする。

```@/layouts/SinglePage.vue
<template lang="pug">
  .page
    Header

    Breadcrumb(v-bind:breadcrumbs="breadcrumbs")

    article
      .title
        h1
          | {{ title }}

      router-view

    Footer
</template>

<script>
  import Header from '@/components/Header';
  import Breadcrumb from '@/components/Breadcrumb';
  import Footer from '@/components/Footer';

  export default {
    name: 'SinglePage',
    components: {
      Header,
      Breadcrumb,
      Footer,
    },
    computed: {
      title() {
        // タイトルがvue-routerのmetaフィールドで指定されているか調べる
        if( this.$route.matched.some( obj => obj.meta.title ) ){
          // 存在するなら使う
          return this.$route.meta.title
        }
        // ない場合
        return '表題無設定'
      },
      breadcrumbs() {
        // パンくずの定義がvue-routerのmetaフィールドでされているか調べる
        if( this.$route.matched.some( obj => obj.meta.breadcrumbs ) ){
          // 存在するなら使う
          return this.$route.meta.breadcrumbs
        }
        // ない場合は、HOMEとだけ表示させる
        return
      }
    },
  };
</script>
```

こいつは、ページのDOMレイアウトを司ってるだけに徹してもらう。あと、vue-routerに定義された`meta`フィールドがちゃんとあるかどうか、存在を確認させて、存在すればページタイトルとかにも使う。（`title`要素もここで考慮したほうがいいかも）パンクズも、そのまま存在すれば引き継ぐ。

なお、さっきも書いた通り、ここでの`<router-view>`が、`router/index.js`で定義した`children`配下のパスに合致した`component`に対応して置き換わる。難しいこと言ってるがパズルみたいなもんだ、実行すればわかるだろ。

あとは必要なページの中身を用意してみる。

```@/components/SectionOne.vue
<template lang="pug">
　　section
　　　　h2 うんこはえいえんのともだち
  p ...
</template>
<script>
  export default {
    name: 'SectionOne',
  };
</script>
```

```@/components/SectionTwo.vue
<template lang="pug">
　　section
　　　　h2 ひろでんでんしゃでちんちんぶらぶら
  p ...
</template>
<script>
  export default {
    name: 'SectionTwo',
  };
</script>
```

```@/components/PageNotFound.vue
<template lang="pug">
　　section
　　　　h2 名称未設定
  p ...
</template>
<script>
  export default {
    name: 'PageNotFound',
  };
</script>
```

いいですね。本質的な部分のみコンポーネント化されていて、とてもシンプルだと勝手に思い込む。

あとはパンくずだが、まあオブジェクトをもらって`v-for`させるだけである。

```@/components/Breadcrumb.vue
<template lang="pug">
  nav
    ul
      li
        router-link(to="/")
          | HOME
      li(v-for="list in breadcrumbs")
        router-link(v-bind:to="list.path")
          | {{ list.name }}
</template>
<script>
  export default {
    name: 'Breadcrumb',
    props: [
      'breadcrumbs'
    ]
  };
</script>
```

ここまでコンポーネント化されているので、必要があれば別にvue-router側でパンくずの定義をせず、APIとかあるならコンポーネント側で`computed`して投げる形も良いと思う。

とにかくこうすると、量産ページ増えても、`section`要素の中身をコンポーネントとして増やしていくだけでページ作れるので、よかったんじゃないかなーと思いました。まる。