本一覧ページを例にルートを拡張してページネーションを静的化する処理を実装していきます。実際のページネーションの処理は省略しています。
ルートを拡張する
nuxt.config.jsのrouterプロパティにextendRoutesオプションを追加することで、Nuxt.js によって作成されたルートを拡張することができます。今回は本一覧ページにページネーションを拡張するので以下のような実装になります。
・nuxt.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | ... router: { extendRoutes (routes, resolve) { routes.push({ path: '/books/page/:p', component: resolve(__dirname, 'pages/books/index.vue'), name: 'books-pager' }) } }, ... |
ちなみに/libraries/1(ライブラリID)/books/page/1のように間にID(例ではライブラリID)を挟んでルートを拡張したい場合は以下のような感じになります。page構成はpages/libraries/_libraries/reviews.vueでファイルを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | ... router: { extendRoutes (routes, resolve) { routes.push({ path: '/libraries/:libraries/books/page/:p', component: resolve(__dirname, 'pages/libraries/_libraries/books.vue'), name: 'libraries-books-pager' }) } }, ... |
・extendRoutesオプション
generateのタイミングでページネーションに必要なデータを渡す
ページネーション用にルートを拡張したら、必要なページの生成とページごとのデータをpayloadで渡していきます。例として本のデータと総件数をもとにページの生成をしています。
10のところは1ページあたりに表示するデータ数で、とりあえずそのまま書いてますがconfigファイルを用意して設定しておきましょう。総件数を10で割った余りが0とそうではない場合で条件分岐し、その回数分ループするようにしています。これは例えば総件数が20件の場合は10で割った余りが0であり、20 / 10で2回分ループします。総件数が21件の場合は10で割った余りが0でないため(20 / 10) + 1となり3回分ループします。1ページに表示できる件数は10件までであるため、このようなロジックになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ... const books = … // 取得処理省略 const booksTotalCount = ... // 取得処理省略 const loops = booksTotalCount % 10 === 0 ? booksTotalCount / 10 : parseInt(booksTotalCount / 10) + 1 return [...Array(loops)].map((_, index) => ({ route: `/books/page/${index + 1}`, payload: { books, totalCount: booksTotalCount } })) ... |
generateで渡されたデータをそれぞれのページで受け取る
ページネーションのページごとにpayloadで渡されたデータから表示分のデータと総件数をstoreにセットします。mapGettersでstoreからデータを取り出してPagerコンポーネントにデータを渡しています(Pagerコンポーネントの実装部分は省略)。payloadで渡されない場合は別途APIから取得するようにしています。
・pages/books/index.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | … <Pager v-if="totalCount" :page-number="param" :per-page="perPage" :total-count="totalCount" :base-path="'/books'" /> … <script> import { mapGetters } from 'vuex' export default { async asyncData ({ store, payload, params }) { const perPage = 10 const param = Number(params.p) || 1 const offset = perPage * (param - 1) if (payload) { store.commit('books/setBooks', { books: payload.books.slice(offset, offset + perPage) }) store.commit('books/setTotalCount', { totalCount: payload.totalCount }) } else { await Promise.all([ store.dispatch('books/fetchBooks', { limit: perPage, offset }), ]) } return { param, perPage } }, computed: { ...mapGetters('books', ['books']), ...mapGetters('books', ['totalCount']) } }; </script> |