mintsu's blog

Nuxt.js でコンポーネント作成。 ブログのモジュールを作成する

2019-07-21 01:00:00
フロントエンド

Nuxt.js でコンポーネント作成。 ブログのモジュールを作成する

Nuxt.js でコンポーントの作成方法について記載します。
ブログなどで、人気ランキングモジュールや、関連記事モジュールなど、複数のページで共通の情報を表示する場合があります。
そういった場合にコンポーネントとして切り出しておくことで、共通化することができます。

目次

作りたいもの

ブログのモジュールとして、同一カテゴリの記事を表示するコンポーネントを作成します。

実際のブログで運用しているイメージとしては下記の様なものになります。(このブログ自体のもの)
作りたいもの

今回は、少し簡略化してコンポーネントに切り分けて、コンポーネントを表示するだけのアプリケーションを作ってみます。

サンプル

環境・利用技術

今回は下記のVue, Nuxt関連の技術を扱って作っていきます。

  • Vue.js
  • Nuxt.js
  • Vuetify
  • Vuex

データソース

今回はデータソースは json に書き込んだブログ記事の情報を読み込むことにします。

{
  "contentsMap": {
    "id1": {
      "title": "テスト記事1",
      "description": "テスト記事1",
      "category": "category1",
      "body": "テスト記事1"
    },
    "id2": {
      "title": "テスト記事2",
      "description": "テスト記事2",
      "category": "category1",
      "body": "テスト記事2"
    },
    "id3": {
      "title": "テスト記事3",
      "description": "テスト記事3",
      "category": "category2",
      "body": "テスト記事3"
    },
    "id4": {
      "title": "テスト記事4",
      "description": "テスト記事4",
      "category": "category2",
      "body": "テスト記事4"
    },
    "id5": {
      "title": "テスト記事5",
      "description": "テスト記事5",
      "category": "category2",
      "body": "テスト記事5"
    },
    "id6": {
      "title": "テスト記事6",
      "description": "テスト記事6",
      "category": "category1",
      "body": "テスト記事6"
    }
  }
}

上記jsonの内容を contents/contentsMap.jsonという名前で保存しておきます。

contents/
└── contentsMap.json

この情報を今回はVuexで管理します。
実際にはAPI等で引いて利用する場合もあると思いますが、その場合もVuexで管理すれば同じように扱えるかと思います。

Vuex

vuex自体に関しては、以前にこちらの記事を書いています。
Nuxt.js で Vuex を使う | mintsu's blog

Vuexを利用するため、 store ディレクトリ以下に記事を管理するvuexファイルとしてarticle.jsを作成します。

store/
└── article.js

vuexのファイルの内容は下記になります。

import { contentsMap } from '~/contents/contentsMap.json'

export const state = () => ({
  articleList: contentsMap
})

export const getters = {
  findArticlesByCategory: state => (category) => {
    return Object.values(state.articleList).filter(a => a.category === category)
  }
}

contentsMap.jsonを読み込んで、 state に設定します。

今回は参照しかないため、gettersのみ定義します。
gettersの内容は findArticlesByCategory というメソッドを定義し、カテゴリ名を指定してcontentsMap.から指定したカテゴリの記事情報のみを返却します。

ここまでで、データソース取得の準備は整いました。

コンポーネントを作成する

ここではコンポーネントはcomponentsディレクトリ以下に置くことにします。

components/
└── CategoryArticleList.vue

コンポーネントの内容は下記のようになります。

<template>
  <v-layout row wrap>
    <v-flex x12 sm12 md12>
      <h3 class="headline">{{ category }} カテゴリの記事</h3>
    </v-flex>
    <v-flex v-for="(article, idx) in articleList" :key="idx" xs12 sm12 md12>
      <v-card style="width: 100%">
        <v-card-text>
          <p>{{ article.title }}</p>
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>

<script>
export default {
  props: { // propsを使うと引数を受け取れるようになる
    category: {
      type: String,
      required: true
    }
  },
  computed: {
    articleList() {
      return this.$store.getters[
        'article/findArticlesByCategory'
      ](this.category)
    }
  }
}
</script>

ポイントとしてはカテゴリ名をpropsで受け取れるようにしているところです。
propsで受け取ったカテゴリを、 computed でvuexから取得するときに利用します。

computedarticleListメソッド内でVuexのgetterを呼び出します。
下記が該当の部分です。

this.$store.getters['article/findArticlesByCategory'](this.category)

Vuexのモジュールモードで引数ありの場合はこのような指定になります。
引数にpropsで受け取ったカテゴリを指定することで、特定のカテゴリの記事リストを取得しています。

コンポーネントの表示

作成したコンポーネントを表示してみます。
下記はpages側のvueファイルです。

pages/
└── componentSample.vue

componentSample.vue

<template>
  <v-layout column justify-center align-center>
    <v-flex xs12 sm8 md6>
      <CategoryArticleList category="category1" /> // コンポーネントの利用箇所
    </v-flex>
  </v-layout>
</template>

<script>
import CategoryArticleList from '~/components/CategoryArticleList.vue' // コンポーネント読み込み
export default {
  components: {
    CategoryArticleList // コンポーネントの登録
  }
}
</script>

コンポーネントを利用するためには、<script>内でコンポーネントの登録をする必要があります。 インポートして、componentsでインポートしたコンポーネントを登録します。

import CategoryArticleList from '~/components/CategoryArticleList.vue' // コンポーネント読み込み
export default {
  components: {
    CategoryArticleList // コンポーネントの登録
  }
}
</script>

コンポーネントを登録すると、カスタム要素としてテンプレート側で利用できるようになります。
上の例ではテンプレート側でCategoryArticleListというタグとして利用できるようになっています。
属性のcategoryはコンポーネント作成時に使ったpropsと対応します。

<CategoryArticleList category="category1" />

実際に表示してみた結果がこちらになります。
結果画面

他のページでも、同じようにコンポーネントの登録さえすれば、CategoryArticleListというタグを呼び出だすだけでカテゴリ記事リストのモジュールが表示できるので、再利用もでき、簡潔に書けるため便利ですね。

実際に作った今回のサイト
component-sample

最後に

今回のポイント

  • コンポーネントを使うことで、共通のUIなどを定義できる
  • データの受け渡しはpropsを使う
  • コンポーネントの利用側は、使うコンポーネントを登録することで、カスタム要素として利用できる

関連記事