TECH BOX

Technology blog from Web Engineer

この記事は最終更新日から4年以上経過しているため正確ではないかもしれません

ページャリストの作り方

※一部ロジック間違いがあったので2019/08/22に修正

ページャには大きく分けて2種類の表示方法があります。
1つは左が常にカレントページ、もう一つは中心がカレントページ。

左がカレント

pager_left

中心がカレント

pager_center

それぞれページリストをどう算出するかのロジックを紹介します。
※ロジックは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]

上記ロジックも総ページを超えたページ数をカレントとして渡した場合でも総ページ数をもとにしたリストを返却しますが、エラーとして返してもいいかもしれません。