はじめに
本投稿は、 【Vue.js】ページネーションコンポーネント(ページ遷移ごとにデータを取得するタイプ) | Wood-Roots:blog にて Vue.js 2 で書かれたページネーションのシングルファイルコンポーネント (SFC) を Vue.js 3 で書き直したものです。
元となった 【Vue.js】ページネーションコンポーネント(ページ遷移ごとにデータを取得するタイプ) | Wood-Roots:blog に感謝申し上げます!
また、本投稿は、本ブログの Vue.js 3 で flatpickr をラップした SFCその2 。ページ移動時に発生していたエラーを解消する – oki2a24 の続きとなります。
書いたコードの構成
laravel/resources/js/router/index.js
: サンプルページを表示するためのルーティングを追加した。laravel/resources/js/views/SamplePagination.vue
: ページネーション SFC を利用する側のページ。laravel/resources/js/components/BasePagination.vue
: ページネーション SFC 本体。
コード
laravel/resources/js/router/index.js
です。サンプルページを表示するためのルーティングを追加しました。差分を表示します。
$ git diff laravel/resources/js/router/index.js
diff --git a/laravel/resources/js/router/index.js b/laravel/resources/js/router/index.js
index bc9d99a..e159aa4 100644
--- a/laravel/resources/js/router/index.js
+++ b/laravel/resources/js/router/index.js
@@ -3,6 +3,7 @@ import ExampleComponent from "../components/ExampleComponent.vue";
import SampleDropzone from "../views/SampleDropzone.vue";
import SampleFlatpickr from "../views/SampleFlatpickr.vue";
import SampleModal from "../views/SampleModal.vue";
+import SamplePagination from "../views/SamplePagination.vue";
import SampleVueFlatpickr from "../views/SampleVueFlatpickr.vue";
import SampleSelect2 from "../views/SampleSelect2.vue";
import Vue3Dropzone from "../views/Vue3Dropzone.vue";
@@ -40,6 +41,11 @@ const routes = [
name: "SampleModal",
component: SampleModal,
},
+ {
+ path: "/sample_pagination",
+ name: "SamplePagination",
+ component: SamplePagination,
+ },
{
path: "/sample_select2",
name: "SampleSelect2",
$
laravel/resources/js/views/SamplePagination.vue
: ページネーション SFC を利用する側のページです。
<template>
<div class="container">
<h1>SamplePagination</h1>
<p>ページネーションを何件表示するか(showPages): {{ showPages }}</p>
<p>現在のページ(currentPage): {{ currentPage }}</p>
<p>総件数(totalCount): {{ totalCount }}</p>
<p>総ページ数(totalPages): {{ totalPages }}</p>
<p>1ページあたりの表示件数(perPage): {{ perPage }}</p>
<hr />
<p>クリックしたページ数: {{ clickedPageNumber }}</p>
<base-pagination
:show-pages="showPages"
:current-page="currentPage"
:total-count="totalCount"
:total-pages="totalPages"
:per-page="perPage"
@currentPage="changePage"
/>
</div>
</template>
<script>
import { ref } from "@vue/reactivity";
import BasePagination from "../components/BasePagination.vue";
export default {
name: "SamplePagination",
components: { BasePagination },
setup() {
const showPages = ref(10);
const currentPage = ref(3);
const totalCount = ref(111);
const totalPages = ref(12);
const perPage = ref(10);
const clickedPageNumber = ref(0);
const changePage = (pageNumber) => {
clickedPageNumber.value = pageNumber;
};
return {
changePage,
clickedPageNumber,
currentPage,
perPage,
showPages,
totalCount,
totalPages,
};
},
};
</script>
laravel/resources/js/components/BasePagination.vue
: ページネーション SFC 本体です。
<template>
<div v-if="totalPages" class="row py-3 justify-content-center">
<div class="col-auto">
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="page-item" :class="{ disabled: currentPageEdited == 1 }">
<a class="page-link" href="#" @click.prevent="setPage(1)"
><<</a
>
</li>
<li class="page-item" :class="{ disabled: currentPageEdited == 1 }">
<a
class="page-link"
href="#"
:class="{ disable: currentPageEdited == 1 }"
@click.prevent="setPage(currentPageEdited - 1)"
>
<</a
>
</li>
<li
v-for="num in showPagesFix"
:key="num"
class="page-item"
:class="{ active: numFix(num) == currentPageEdited }"
>
<template v-if="numFix(num) == currentPageEdited">
<span class="page-link">{{ numFix(num) }}</span>
</template>
<a
v-else
class="page-link"
href="#"
@click.prevent="setPage(numFix(num))"
>{{ numFix(num) }}</a
>
</li>
<li
class="page-item"
:class="{ disabled: currentPageEdited == totalPages }"
>
<a
class="page-link"
href="#"
@click.prevent="setPage(currentPageEdited + 1)"
>></a
>
</li>
<li
class="page-item"
:class="{ disabled: currentPageEdited == totalPages }"
>
<a class="page-link" href="#" @click.prevent="setPage(totalPages)"
>>></a
>
</li>
</ul>
</nav>
</div>
</div>
</template>
<script>
import { computed, ref, watch } from "@vue/runtime-core";
export default {
name: "BasePagination",
props: {
showPages: {
default: 1,
require: false,
type: Number,
}, //ページネーションを何件表示するか
currentPage: {
default: 1,
require: false,
type: Number,
}, //現在のページ
totalCount: {
default: 1,
require: false,
type: Number,
}, //総件数
totalPages: {
default: 1,
require: false,
type: Number,
}, //総ページ数
perPage: {
default: 20,
require: false,
type: Number,
}, //1ページあたりの表示件数
},
emits: ["currentPage"],
setup(props, { emit }) {
const currentPageEdited = ref(props.currentPage);
//ページ番号を計算する
const numFix = (num) => {
const ajust = 1 + (props.showPages - 1) / 2;
let result = num;
//前ページがマイナスになる場合は1からはじめる
if (currentPageEdited.value > props.showPages / 2) {
result = num + currentPageEdited.value - ajust;
}
//後ページが最大ページを超える場合は最大ページを超えないようにする
if (currentPageEdited.value + props.showPages / 2 > props.totalPages) {
result = props.totalPages - props.showPages + num;
} //総ページ数が表示ページ数に満たない場合、連番そのまま
if (props.totalPages <= props.showPages) {
result = num;
}
return result;
};
//総記事数が表示ページ数以下の場合に調整する
const showPagesFix = computed(() => {
if (props.totalPages < props.showPages) {
return props.totalPages;
} else {
return props.showPages;
}
});
//ページネーションを複数設置したときの対応
watch(
() => props.currentPage,
(newValule) => {
currentPageEdited.value = newValule;
}
);
//何ページ目を表示するか
const setPage = (page) => {
//マイナスにならないようにする
if (page <= 0) {
currentPageEdited.value = 1;
}
//最大ページを超えないようにする
else if (page > props.totalPages) {
currentPageEdited.value = props.totalPages;
} else {
currentPageEdited.value = page;
}
//親コンポーネントに現在のページを送る
emit("currentPage", currentPageEdited.value);
};
return { currentPageEdited, numFix, setPage, showPagesFix };
},
};
</script>
おわりに
なんとなく動きが怪しいところが見られました (4.5 ページなどが出る) 。これは移植前からなのか、移植したからなのかはわかりません。
これを直したり、自身が扱いやすいようにリファクタリングできたら、と思います。
以上です。