なにこれ
VuetifyのDataTableとPaginationを使った検索一覧画面でページングの状態を、ルーティングをまたいで保存しておきたい。という要望を満たすため、ページングの状態をVuexで管理する方法をメモします。 DataTableだけだとすんなりできますが、Paginationもあわせて使う場合は少し雑な実装になってしまいます。
やり方
まずはストアに以下のように定義します。 アクションには「ページングオブジェクト保存」と「ページングオブジェクトのページのみ保存」の2種類を用意します。
サンプル実装(Vuex側)
export default new Vuex.Store({
state: {
pagination: {
page: 1,
rowsPerPage: 20,
sortBy: 'id',
descending: false,
},
},
getter: {
getPagination: state => state.pagination,
},
actions: {
SAVE_PAGINATION({ commit }, payload) {
const {
page,
rowsPerPage,
sortBy,
descending,
} = payload;
commit('savePagination', {
page,
rowsPerPage,
sortBy,
descending,
});
},
SAVE_PAGINATION_PAGE({ commit }, payload) {
const { page } = payload;
commit('savePaginationPage', page);
},
},
mutations: {
savePagination(state, pagination) {
state.pagination = pagination;
},
savePaginationPage(state, page) {
state.pagination.page = page;
},
},
});
次にコンポーネント側です。
v-data-table
,v-pagination
ともにVuexのページングオブジェクトを参照し、UIで変更があればVuexのアクションを呼び出します。それぞれのタグで微妙にやり方が違います。
もう少しスマートにしたかったのですが、実際動かしてみた感じだとどうしてもスマートにはできませんでした。
サンプル実装(コンポーネント側)
<template>
<div>
<!--
ページングはpaginationに任せるのでhide-actionsを指定している
pagination.syncにはgetterとsetterを持たせたpaginationを指定
-->
<v-data-table
:pagination.sync="pagination" :items="items"
hide-actions
>
<!-- テーブルの中身 -->
</v-data-table>
<!--
valueでVuexのページングオブジェクトを参照して
UI側からの変更は@inputでVuexのアクションを呼び出す
-->
<v-pagination
:length="pages"
v-if="pages >= 2"
:total-visible="7"
:value="paginationPage" @input="savePaginationPageInStore({ page: $event })" />
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
date() {
return {
items: []
}
},
computed: {
...mapGetters({
paginationInStore: 'getPagination',
}),
pagination: { // Vuexのページングオブジェクトを参照 get() { return this.paginationInStore; }, // UI側から変更があった場合はSetter経由でVuexのアクションを呼び出す set(pagination) { this.savePaginationInStore(pagination); }, },
// ページネーション参照用
paginationPage() { return this.paginationInStore.page; }, // ページネーション用ページ数算出メソッド
pages() {
if (this.pagination.rowsPerPage == null || this.items == null || this.items.length === 0) {
return 0;
}
return Math.ceil(this.items.length / this.pagination.rowsPerPage);
},
},
methods: {
...mapActions({
savePaginationInStore: 'SAVE_PAGINATION', savePaginationPageInStore: 'SAVE_PAGINATION_PAGE', }),
},
}
</script>
これでルーティングをまたいでページングオブジェクトを保持できるようになりました。
実用の場面では、検索条件もVuexに持たせて、ページングオブジェクトと連動させて使います。
以上です🍅