※一部ロジック間違いがあったので2019/08/22に修正
ページャには大きく分けて2種類の表示方法があります。
1つは左が常にカレントページ、もう一つは中心がカレントページ。
左がカレント
中心がカレント
それぞれページリストをどう算出するかのロジックを紹介します。
※ロジックはJavaScriptで記述していますが、多言語でも計算方法自体は変わりません
共通して注意する点
どの方法にするにしても、共通して下記点に注意する必要があります。
- カレントページがページ総数に近づいた時
- 総ページ数が表示個数より小さい場合
常に左端がカレントページの場合
カレントページが常に0番目なので計算はカレントページを起点として計算すれば良いので簡単です。
/**
* @param {number} total - 総ページ数
* @param {number} display - 1ページに表示する数
* @param {number} current - 現在のページ
* @return {number[]}
*/
function Pager (total, display, current) {
// 総ページ数が表示個数より小さい場合は総ページ数を上限とする
display = total < display ? total : display
let num = current
// displayはlength扱いなので-1をした予測合計値
const prediction = current + (display - 1)
// 総ページ数を超えた場合は、超えた数だけマイナス
if (prediction > total) {
num = current + (total - prediction)
}
const pages = []
for (let i = 0; i < display; i++) {
pages.push(num + i)
}
return pages
}
console.log(Pager(10, 5, 1)) // [1, 2, 3, 4, 5]
console.log(Pager(10, 5, 4)) // [4, 5, 6, 7, 8]
console.log(Pager(10, 5, 9)) // [6, 7, 8, 9, 10]
console.log(Pager(10, 5, 11)) // [6, 7, 8, 9, 10] ※カレントを総ページより大きくした場合
console.log(Pager(3, 5, 1)) // [1, 2, 3]
console.log(Pager(3, 5, 3)) // [1, 2, 3]
console.log(Pager(3, 5, 4)) // [1, 2, 3] ※カレントを総ページより大きくした場合
上記ロジックは総ページを超えたページ数をカレントとして渡した場合でも総ページ数をもとにしたリストを返却しますが、エラーとして返してもいいかもしれません。
カレントページを中心にする場合
カレントページを中心にする場合は計算が少し複雑になります。
基本は表示数の中心値からマイナスしたページ数(5だったら2)からスタートするようになります。
また、カレントページが中心に来るまでの処理という条件が増えます。
例えば、リストを5個表示の場合でカレントページが1〜3の場合は常に[1,2,3,4,5]
にならなければいけません。
※下記の一部ロジックに間違いがあったので2019/08/22に修正
/**
* @param {number} total - 総ページ数
* @param {number} display - 1ページに表示する数
* @param {number} current - 現在のページ
* @return {number[]}
* @constructor
*/
function Pager (total, display, current) {
// 総ページ数が表示個数より小さい場合は総ページ数を上限とする
display = total < display ? total : display
// 中心になるindex
const centerIdx = Math.floor(display / 2)
// 表示する最後のページを予測
const prediction = current + centerIdx
// リストのスタート値
let num = current - centerIdx
if (current <= (centerIdx + 1)) {
// カレント値が中心値より少ない場合は1からスタート
num = 1
} else if (prediction > total) {
// 総ページ数を超える場合は、総ページ数から表示ページ数を引く
// display - 1は最終ページを除く数
num = total - (display - 1)
}
const pages = []
for (let i = 0; i < display; i++) {
pages.push(num + i)
}
return pages
}
console.log(Pager(10, 5, 1)) // [1, 2, 3, 4, 5]
console.log(Pager(10, 5, 3)) // [1, 2, 3, 4, 5]
console.log(Pager(10, 5, 4)) // [2, 3, 4, 5, 6]
console.log(Pager(10, 5, 9)) // [6, 7, 8, 9, 10]
console.log(Pager(10, 5, 10)) // [6, 7, 8, 9, 10]
console.log(Pager(10, 5, 11)) // [6, 7, 8, 9, 10] ※カレントを総ページより大きくした場合
console.log(Pager(3, 5, 1)) // [1, 2, 3]
console.log(Pager(3, 5, 3)) // [1, 2, 3]
console.log(Pager(20, 6, 8)) // [5, 6, 7, 8, 9, 10]
上記ロジックも総ページを超えたページ数をカレントとして渡した場合でも総ページ数をもとにしたリストを返却しますが、エラーとして返してもいいかもしれません。