Nuxt.jsにページネーションを付けるために、Vue.jsのパッケージVuejs-paginateを導入した。
導入方法
Vuejs-paginateに限らず、Nuxt.jsで外部パッケージを追加するとwindow is not defined
のエラーが出るので、pluginを作成してグローバルコンポーネントとして登録する。
plugins/vuejs-paginate.js
import Vue from 'vue';
import Paginate from 'vuejs-paginate';
Vue.component('paginate', Paginate)
nuxt.config.js
plugins: [
{src: '~/plugins/vuejs-paginate', ssr:false },
],
プラグインのbuildオプションをclientでのみ実行するように設定する。Nuxt.js 2.14.x以降はmode:'cliant'
といった記述方法が非推奨になったため、ssr:false
とする。
ページネーションメソッドの設定
index.vue
<script>
export default {
data () {
return {
items: '',
parPage: '',
currentPage: '',
};
},
methods: {
clickCallback: function (pageNum) {
this.currentPage = Number(pageNum);
}
},
computed: {
posts: function() {
let current = this.currentPage * this.parPage;
let start = current - this.parPage;
return this.items.slice(start, current);
},
getPageCount: function() {
return Math.ceil(this.items.length / this.parPage);
}
},
async asyncData ({ $content }) {
const items = await $content('post')
.sortBy('published', 'desc')
.fetch()
const parPage = 12;
const currentPage = 1;
return { items, parPage, currentPage }
},
}
</script>
dataプロパティ
items
…アイテムの配列。nuxt/contentで記事を作成している当ブログの場合はpostフォルダ内から取得している。parPage
…1ページに表示するアイテム数currentPage
…現在のページ番号(1から始まる)
methods
clickCallback
…ページネーションクリック時にcurrentPage
へページ番号を設定
computed
posts
…現在のページのアイテムを返す。当ブログの場合はCard
コンポーネントへも渡している。getPageCount
…ページネーションの最大ページ数(items
をparPage
で割って切り上げ)
テンプレート部分
index.vue
<template>
<main role="main">
<CardList :posts="posts"/>
<client-only placeholder="Loading...">
<paginate v-if="(getPageCount > 1)"
:page-count="getPageCount"
:page-range="3"
:margin-pages="2"
:click-handler="clickCallback"
:prev-text="'前へ'"
:next-text="'次へ'"
:container-class="'pagination flex justify-center mb-6'"
:page-class="'c-pagination-item'"
:page-link-class="'c-pagination-item__link'"
:prev-class="'c-pagination-btn c-pagination-prev'"
:prev-link-class="'c-pagination-btn__link'"
:next-class="'c-pagination-btn c-pagination-next'"
:next-link-class="'c-pagination-btn__link'"
:hide-prev-next="true"
>
</paginate>
</client-only>
</main>
</template>
以下は当ブログ独自に追加したもの
<client-only placeholder="Loading..."> </client-only>
の部分はwindow is not defined
エラー対策。v-if="(getPageCount > 1)"
…デフォルトだと1ページのみの場合もページネーションが出てしまうので、2ページ以上の時に表示されるようにするための処理。
プロパティ
当ブログで使用しているものを抜粋
名前 | タイプ | 説明 |
---|---|---|
page-count |
数値 | 総ページ数(必須)。上記テンプレートの場合getPageCount に渡されている。 |
page-range |
数値 | 表示されるページ数(アクティブページの前後に同じページ数表示されるようにするため、奇数推奨)。デフォルト値:3 |
margin-pages |
数値 | 余白のページ表示数。デフォルト値:1 |
prev-text |
文字列 | 「前へ」ボタンのテキスト。HTML使用可。デフォルト値:prev |
next-text |
文字列 | 「次へ」ボタンテキスト。HTML使用可。デフォルト値:next |
click-handler |
関数 | ページをクリックした時に呼び出すメソッド。クリックされたページ番号をパラメーターとして使用する。 |
container-class |
文字列 | ページネーションを囲むコンテナのclass |
page-class |
文字列 | ページ要素のliタグのclass |
page-link-class |
文字列 | ページ要素のaタグのclass |
prev-class |
文字列 | 「前へ」ボタン要素liタグのclass |
prev-link-class |
文字列 | 「前へ」ボタン要素aタグのclass |
next-class |
文字列 | 「次へ」ボタン要素liタグのclass |
next-link-class |
文字列 | 「次へ」ボタン要素aタグのclass |
hide-prev-next |
真偽 | 前/次のページがない場合はボタンを表示しない。デフォルト値:false (表示) |
CSSでスタイルを当てる
container-class
にはtailwindcssのflex
justify-center
mb-6
のclassが当てられているので、それ以外のパーツをcssで装飾する。
.c-pagination-btn__link,
.c-pagination-item__link {
border: solid 2px #3A3F58;
border-radius: 4px;
text-align: center;
padding: .5rem 1rem;
margin: 0 .25rem;
display: block;
}
.c-pagination-btn__link:hover,
.c-pagination-item__link:hover {
background-color: #3A3F58;
color: #fff;
}
.active .c-pagination-item__link {
background-color: #3A3F58;
color: #fff;
pointer-events: none;
}