12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Nuxt.js】Contentfulで作ったブログにPaginationを付けるまで

12
Last updated at Posted at 2020-03-23

サイトのInformationをMicroCMSで作ろうとしたとき、表側の表示はできたのですが、リンク先や記事ページを自動で生成するにはどうしたらいいのか全然わかリませんでした。

今更wordpressに戻るのも嫌なので調べていくとContentfulでブログを作っている情報がでてきたのでNuxt.js+Contentful+Netlifyでまず作り方を覚えていこうと思います。

用意するもの

Nuxt.jsだけではブログを公開することはできないので下記のサービスやツールを組み合わせていきます。
Nuxt.js
今回ブログのベースを構築します。

Vuetify
UIのフレームワークとして利用します。

Contentful
ヘッドレスCMS、ブログのエディターとして記事をこちらで作成します。

Github
ソース管理と本番にデプロイするために必要です。

Netlify
本番に公開するためのサーバーです。Githubなどと連携することで簡単にデプロイすることができます。

早速構築していく

今回は様々な方法を調べましたがこちらの記事がすごく丁寧でわかりやすかったので途中まではそのままの手順で進めていきました。
[Nuxt.jsとContentfulで作るマイブログ]
(https://blog.cloud-acct.com/categories/myblog)

Nuxtの設定

まずはNuxtを設定します。UIフレームワークはVuetifyにします。
Nuxtのインストール

Netlifyの登録

こちらは記事内ではBitbucketで登録となっていましたがGithubで登録しました。
※他にGitlabのアカウントでも登録できます。

Contentfulの登録

こちらも登録していき、コンテンツを作成していきます。

参考にした記事どうりに続けていけばそれなりのブログの形ができあがります。
スクリーンショット 2020-03-23 8.56.31.png

ページネーションがない

ブログを作っていくうちに気づいたのですが記事数が増えると非常に長いサイトになってしまします。
そこで記事表示の制限を10投稿ほどにして、残りの投稿はページネーションをつけようと思いました。

ページネーションはVuetifyのv-paginationを利用できるので、こちらの記事を参考に作成しました。
[【vue.js】 Vuetifyで簡単ページネーション(Paginations)]
(https://reffect.co.jp/vue/vuetify-simple-pagination)

表示数を設定する

記事データ自体は...mapState(['posts'])で取得しているので
取得したデータをmountedに書き込みます。


mounted: function(){
  this.posts
},

1ページに表示させる数を設定する

1ページに表示させる数を設定します。
表示数をpageSizeにデータを保持にdisplayListsをdataプロパティに追加します。


data () {
  return {
    displayLists: [],
    pageSize: 10,
  }
},

追加したdisplayListsをpageSizeを使って設定します。


mounted: function(){
  this.posts
  this.displayLists = this.posts.slice(0,this.pageSize);
},

v-forでdisplayListsに差し替えます。

<v-col
  v-for="post in displayLists"
  :key="post.index"
  cols="12"
  sm="6"
  lg="4"
  xl="3"
>

ページネーションと連携する

ページネーションと連携するために下記の用に書きます。

ページ番号が1であれば、slice(0,10)となり、ページ番号が2であれば、slice(10,20)になり10投稿ずつ表示されます。
これでpageNumberに合わせて表示する内容を変更できます。

methods: {
  pageChange: function(pageNumber){
    this.displayLists = this.posts.slice(this.pageSize*(pageNumber -1), this.pageSize*(pageNumber));
  },
},

lengthメソッドを設定する

ページネーションのページの数をlengthメソッドの設定でおこないます。

this.length = Math.ceil(this.posts.length/this.pageSize);

dataプロパティに新たにlengthを追加

data () {
  return {
    page: 1,
    length:0,
    displayLists: [],
    pageSize: 10,
  }
},

v-paginationに追加

<v-pagination
  v-model="page"
  :length="length"
  @input = "pageChange"
></v-pagination>

これで準備完了です。

# ソースをまとめる
最終作成したソースはこちらになります。


<template>
  <v-container fluid>
    <v-row
      justify="center"
    >
      <v-col
        cols="12"
        sm="11"
        md="10"
        xl="8"
      >
        <v-row v-if="posts.length">
          <v-col
            v-for="post in displayLists"
            :key="post.index"
            cols="12"
            sm="6"
            lg="4"
            xl="3"
          >
            <v-card
              max-width="400"
              class="mx-auto"
            >
              <v-img
                :src="setEyeCatch(post).url"		
                :alt="setEyeCatch(post).title"
                :aspect-ratio="16/9"
                max-height="200"
                class="white--text"
              >
                <v-card-text>
                  <v-chip
                    small
                    dark
                    :color="categoryColor(post.fields.category)"
                    :to="linkTo('categories', post.fields.category)"
                    class="font-weight-bold"
                  >
                    {{ post.fields.category.fields.name }}
                  </v-chip>
                </v-card-text>
                <v-card-title class="align-end fill-height font-weight-bold">
                  {{ post.fields.title }}
                </v-card-title>
              </v-img>

              <v-card-title>
                <nuxt-link
                  :to="linkTo('posts', post)"
                >
                  {{ post.fields.title }}
                </nuxt-link>
              </v-card-title>

              <v-card-text>
                {{ post.fields.publishDate }}
                <span :is="draftChip(post)" />
              </v-card-text>

              <v-list-item three-line style="min-height: unset;">
                <v-list-item-subtitle>
                  {{ post.fields.body }}
                </v-list-item-subtitle>
              </v-list-item>

              <v-card-text>
                <template v-if="post.fields.tags">
                  <v-chip
                    v-for="(tag) in post.fields.tags"
                    :key="tag.sys.id"
                    :to="linkTo('tags', tag)"
                    small
                    label
                    outlined
                    class="ma-1"
                  >
                    <v-icon
                      left
                      size="18"
                      color="grey"
                    >
                      mdi-label
                    </v-icon>
                    {{ tag.fields.name }}
                  </v-chip>
                </template>
              </v-card-text>

              <v-card-actions>
                <v-spacer />
                <v-btn
                  text
                  color="primary"
                  :to="linkTo(`posts`,post)"
                >
                  この記事をみる
                </v-btn>
              </v-card-actions>
            </v-card>
          </v-col>
        </v-row>
        <div v-else class="text-center">
          投稿された記事はありません。
        </div>
      </v-col>
    </v-row>
    <v-pagination
      v-model="page"
      :length="length"
      @input = "pageChange"
    ></v-pagination>
  </v-container>
</template>

<script>
import draftChip from '~/components/posts/draftChip'
import { mapState, mapGetters } from 'vuex' 

export default {
  data () {
    return {
      page: 1,
      length:0,
      displayLists: [],
      pageSize: 10,
    }
  },
  components: {
    draftChip
  },
  computed: {
    ...mapState(['posts']), 
    ...mapGetters(['setEyeCatch', 'draftChip', 'linkTo']),
    categoryColor() {
      return (category) => {
        switch (category.fields.name) {
          case 'RubyOnRails': return '#C73A31'
          case 'Nuxt.js': return '#236244'
          case 'コラム': return 'primary'
          default: return 'grey darken-3'
        }
      }
    }
  },
  mounted: function(){
    this.posts
    this.length = Math.ceil(this.posts.length/this.pageSize);
    this.displayLists = this.posts.slice(this.pageSize*(this.page -1), this.pageSize*(this.page));
  },
  methods: {
    pageChange: function(pageNumber){
      this.displayLists = this.posts.slice(this.pageSize*(pageNumber -1), this.pageSize*(pageNumber));
    },
  },
}
</script>

うまくいきました。

スクリーンショット 2020-03-23 9.55.17.png スクリーンショット 2020-03-23 9.55.21.png

これでwordpressの代わりにモダンなフロントエンドの技術でサイトを構築できそうです。

作ったブログのURLとGithubにソースをアップしています。
https://hirokuma-note.com/
https://github.com/hiroyukiw/nuxt-blog

もっとすっきりしたやり方があれば教えてください。

これまでに参考にしたサイト

Nuxt.jsとContentfulで作るマイブログ
[Nuxt.js / Contentful でJAMstackなブログ開発編]
(https://qiita.com/_takeshi_24/items/7d16dc5d0bc41f5e0779)
Netlifyとは? 〜概要から導入まで〜
NetlifyとGithubを連携させ、サイトのアップロード作業を自動化する方法
[Netlify にお名前.com で取得したドメインを設定する]
(https://contentful-explore.netlify.com/how/netlify-domain-setting)
[【Contentful】入門。Conentfulとは?導入方法・設定手順の解説]
(https://fromscratch-y.work/ja/blog/technology/other/start-contentful/)
[Nuxt.jsにおけるenvファイルの利用(初学者向けハンズオン)]
(https://qiita.com/yfujii1127/items/c77bff6f0177b4ff219e)
[Netlifyで環境変数を設定する方法]
(https://www.suzu6.net/posts/149-netlify-environment-variables/)
[Vueのcomputedとmethodsの「使い分け」を解説]
(https://dev83.com/vue-computed-methods/)
[VuexのStoreはNuxt.jsのマニュアルを見るとすぐ理解できる]
(https://crieit.net/posts/Vuex-Store-Nuxt)
【vue.js】 Vuetifyで簡単ページネーション(Paginations)

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?