☕
Vue 2 + typescript , paginate(ページング 部品) Laravel編
概要:
Vue 2 で、ページング 部品を作るメモとなります
-
コンポーネント化して、親画面から呼び出す形になります
-
props, $emit使用し、親子間双方向データ送信する方法です。
-
表示データは固定変数にしていますが。使用時は api等で取得する形を想定しています
構成
- Vue : 2.6.12
- typescript : 4.7
- Larvavel : 9.14
- node : 14
関連
見た目。ページング部品
参考のコード
コンポーネント
- 子側 ,PaginateBox.vue
data 変数
- childCurrentPage : 現在ページ位置
- pages : 最大ページ数
- this.$emit() の、部分で親側に、データ送信
PaginateBox.vue
<template>
<div class="">
<!--
<h3>PaginateChild</h3>
-->
<nav class="my-2">
<ul class="pagination">
<li class="page-item">
<a @click="first" class="page-link" href="#">«</a>
</li>
<li class="page-item">
<a @click="prev" class="page-link" href="#"><</a>
</li>
<li v-for="i in displayPageRange"
class="page-item"
:class="{active: i-1 === childCurrentPage}">
<a @click="pageSelect(i)" class="page-link" href="#">{{ i }}</a>
</li>
<li class="page-item">
<a @click="next" class="page-link" href="#">></a>
</li>
<li class="page-item">
<a @click="last" class="page-link" href="#">»</a>
</li>
</ul>
</nav>
</div>
</template>
<!-- -->
<style>
</style>
<!-- -->
<script lang="ts">
import Vue from 'vue';
//
interface DataType {
child_num: number,
childCurrentPage: number,
pages: number,
}
//
export default Vue.extend({
props: {
currentPage: {type: Number, default: 0},
size: {type: Number, default: 0},
pageRange: {type: Number, default: 0},
items: {type: Array, default: []},
},
data(): DataType {
return {
child_num: 120,
childCurrentPage: 0,
pages: 0,
};
},
created () {
console.log( "currentPage=", this.currentPage)
console.log( "size=", this.size )
console.log( "pageRange=", this.pageRange )
// console.log( "items=", this.items)
},
computed: {
/**
* ページネーションで表示するページ番号の範囲を取得する
*/
displayPageRange () : any[]{
const half = Math.ceil(this.pageRange / 2);
let start, end;
this.pages = this.pageCount()
if (this.pages < this.pageRange) {
start = 1;
end = this.pages;
} else if (this.currentPage < half) {
start = 1;
end = start + this.pageRange - 1;
} else if (this.pages - half < this.currentPage) {
end = this.pages;
start = end - this.pageRange + 1;
} else {
start = this.currentPage - half + 1;
end = this.currentPage + half;
}
let indexes = [];
for (let i: number = start; i <= end; i++) {
//@ts-ignore
indexes.push(i);
}
return indexes;
},
},
methods: {
/**
* ページ数を取得する
*/
pageCount () : number {
return Math.ceil(this.items.length / this.size);
},
first () {
// console.log("first");
this.childCurrentPage = 0;
this.selectHandler();
},
prev () {
if (0 < this.currentPage) {
this.childCurrentPage--;
this.selectHandler();
}
},
next () {
this.pages = this.pageCount()
if (this.currentPage < this.pages - 1) {
this.childCurrentPage++;
this.selectHandler();
}
},
last () {
this.pages = this.pageCount()
this.childCurrentPage = this.pages - 1;
this.selectHandler();
},
pageSelect (index: number) {
this.childCurrentPage = index - 1;
this.selectHandler();
},
selectHandler () {
this.$emit("recvCurrentPage", this.childCurrentPage);
},
},
})
</script>
-
親側、PaginateTest.vue
-
子側PaginateBox に。props で値を渡す ($emitの処理が、わかりにくい )
-
size : 1ページに表示する件数
-
pageRange : paginateボタンの、最大数
-
items: 配列データ
-
reflectNum : 子から呼ばれる関数
-
reflectNum(value: any) の、valueに値が渡される
PaginateTest.vue
<template>
<div class="container">
<h3>PaginateParent</h3>
<!--
<p>parent_num: {{ currentPage }}</p>
-->
<ul class="list-group">
<li v-for="item in displayItems" class="list-group-item">
{{ item.text }}
</li>
</ul>
<hr />
<PaginateBox
:currentPage="currentPage"
:size = "size"
:pageRange = "pageRange"
:items="items"
@recvCurrentPage='reflectNum'>
</PaginateBox>
</div>
</template>
<!-- -->
<style>
</style>
<!-- -->
<script lang="ts">
import Vue from 'vue';
import PaginateBox from './PaginateBox.vue';
type DataType = {
currentPage: number
size: number
pageRange: number
items: any[],
}
export default Vue.extend({
components: { PaginateBox },
data(): DataType {
return {
currentPage: 0, // 現在のページ番号
size: 10, // 1ページに表示するアイテムの上限
pageRange: 8, // ページネーションに表示するページ数の上限
items: [], // 表示するアイテムリスト
}
},
created () {
try{
//console.log("created")
this.items = [...Array(200)].map((_, i) => {
return {
text: `TestItem: ${i}`
};
});
} catch (e) {
console.error(e);
}
// console.log( "items=", this.items )
},
computed: {
/**
* 現在のページで表示するアイテムリストを取得する
*/
displayItems () : any[] {
const head = this.currentPage * this.size;
return this.items.slice(head, head + this.size);
},
},
methods: {
reflectNum(value: any) : void {
this.currentPage = value;
console.log("reflectNum.parent_num", this.currentPage);
}
}
})
</script>
....
Discussion