VanillaJSで途中省略のページャーを実装する

以前にjQueryを使ったページ送りの実装の記事を投稿しましたが、今回はVanillaJSでページャーが長い場合に途中省略されるタイプのページャーを実装してみます。

サンプルコード

以前と同様、以下のようなjsonデータを用意します。

{
  "data": [
    {
      "title": "記事001",
      "body": "記事001の内容"
    }, {
      "title": "記事002",
      "body": "記事002の内容"
    },
    〜 略 〜
    {
      "title": "記事100",
      "body": "記事100の内容"
    }
  ]
}

一覧とページャーのエリアを用意します。

<div id="js-article"></div>
<div id="js-pager"></div>

以前の記事をjQueryからVanillaJSに変更した上で、ページャーが長い場合に省略するように仕様を変更します。

const pagerOptions = {
  paramKey: 'page', // 何ページ目かを示すパラメータのキー
  articleCount: 10, // 1ページあたりに表示させる記事の件数
  pagerMaxCount: 5 // ページャーの最大数
}

// パラメータから現在のページ番号を取得
const currentNumber = get_current_page_number(pagerOptions['paramKey']);

// data.jsonの取得
fetch('./data.json')
  .then(response => response.json())
  .then(data => {
    generate_article_result(data, currentNumber);
    generate_pager(data, currentNumber);
  })
  .catch(error => {
    console.log('取得に失敗しました。');
  });

/**
 * ページャーの現在のページ数を取得する
 * @param {string} key (required) パラメータのkey
 */
function get_current_page_number(key) {
  // URLからパラメータ取得
  const params = [];
  const param = location.search.substring(1).split('&');
  for(let i = 0; i < param.length; i++) {
    params[i] = param[i].split('=');
  }
  let current = 1;
  for(let i = 0; i < params.length; i++) {
    if(params[i][0] === key) {
      current = parseFloat(params[i][1]);
      break;
    }
  }
  return current;
}

/**
 * 記事の表示
 * @param {object} articleData (required) 記事情報
 * @param {array}  current     (required) 現在のページ数
 */
function generate_article_result(articleData, current) {
  const data = articleData['data'];
  const startNum = (pagerOptions['articleCount'] * (current - 1));
  const endNum = Math.min(startNum + pagerOptions['articleCount'], data.length);
  const articleHtml = data.slice(startNum, endNum).map(article => `
    <div class="article">
      <p class="article_ttl">${article.title}</p>
      <div class="article_body">${article.body}</div>
    </div>
  `).join('');
  document.getElementById('js-article').innerHTML = articleHtml;
}

/**
 * ページャーの表示
 * @param {object} articleData (required) 記事情報
 * @param {array}  current     (required) 現在のページ数
 */
function generate_pager(articleData, current) {
  const data = articleData['data'];
  const articleCount = data.length;

  const pagerLength = Math.ceil(articleCount / pagerOptions['articleCount']); // ページャーの総数
  const pagerMaxCount = pagerOptions['pagerMaxCount']; // ページャーの最大表示件数(最初と最後のページは除く)
  const pagerBeforeLength = Math.ceil(pagerMaxCount / 2) - 1; // 現在のページより前に表示される最大件数
  const pagerAfterLength = Math.floor(pagerMaxCount / 2); // 現在のページより後に表示される最大件数
  let pagerStartNum = current - pagerBeforeLength; // ページャーの表示開始の番号(最初のページは含まない)
  // pagerBeforeLengthの分だけ確保できない場合、2ページ目を開始地点にする
  if(current < pagerBeforeLength + 2) pagerStartNum = 2;
  let pagerEndNum = current + pagerAfterLength; // ページャーの表示終了の番号(最後のページは含まない)
  // pagerAfterLengthの分だけ確保できない場合、最後のページのひとつ前を終了地点にする
  if(current >= pagerLength - pagerAfterLength) pagerEndNum = pagerLength - 1;

  let baseUrl = './';
  baseUrl += '?' + pagerOptions['paramKey'] + '=';

  // 現在のページが存在しない場合は1ページ目にリダイレクト
  if(current > pagerLength) location.href = baseUrl + 1;
  // 記事が0件の場合またはページャーが1件のみの場合は表示しない
  if(pagerLength <= 1) return;

  // ページャーのHTML生成
  let pagerHtml = '<div class="pager">';
  // 前のページに戻るリンク(表示しているページが2ページ目以降の場合のみ表示)
  if (current > 1) {
    pagerHtml += `<a class="pager_prev" href="${baseUrl}${current - 1}">prev</a>`;
  }
  pagerHtml += '<ol class="pager_list">';
  // 先頭のページへのリンク(常に表示)
  pagerHtml += `
    <li class="pager_item${current === 1 ? ' is-current' : ''}">
      <a href="${baseUrl}1">1</a>
    </li>
  `;
  // 省略記号の表示判定(pagerStartNum が2より大きい場合のみ表示)
  if (pagerStartNum > 2) {
    pagerHtml += '<li class="pager_item">...</li>';
  }
  // 現在のページの前後のページ(最初と最後のページは含めない)
  for (let i = pagerStartNum; i <= pagerEndNum; i++) {
    pagerHtml += `
      <li class="pager_item${i === current ? ' is-current' : ''}">
        <a href="${baseUrl}${i}">${i}</a>
      </li>
    `;
  }
  // 省略記号の表示判定(pagerEndNum が最後のページ - 1 未満の場合のみ表示)
  if (pagerEndNum < pagerLength - 1) {
    pagerHtml += '<li class="pager_item">...</li>';
  }
  // 末尾のページへのリンク(常に表示)
  pagerHtml += `
    <li class="pager_item${current === pagerLength ? ' is-current' : ''}">
      <a href="${baseUrl}${pagerLength}">${pagerLength}</a>
    </li>
  `;
  pagerHtml += '</ol>';
  // 次のページへのリンク(表示しているページが最後のページより前の場合のみ表示)
  if (current < pagerLength) {
    pagerHtml += `<a class="pager_next" href="${baseUrl}${current + 1}">next</a>`;
  }
  pagerHtml += '</div>';

  document.getElementById('js-pager').innerHTML = pagerHtml;
}

これで想定したページャーの実装ができました。
ページャー実装のデモページ

ページャーの大まかな仕様としては以下の通りです。

  • 最初のページと最後のページへのリンクは必ず表示する。
  • pagerMaxCountで設定するページャーの最大数は、最初のページと最後のページを除いた最大表示件数を設定する。
    前述の例の場合は5なので、現在のページの前後に2件ずつ表示される。
  • ページ数が一定数より多い場合、一部を省略表示にする。

pagerOptionsのarticleCountとpagerMaxCountを変更して、いくつかのパターンをテストしてみます。

const pagerOptions = {
  paramKey: 'page', // 何ページ目かを示すパラメータのキー
  articleCount: 50, // 1ページあたりに表示させる記事の件数
  pagerMaxCount: 5 // ページ送りの最大数
}

ページャー実装のデモページ2

const pagerOptions = {
  paramKey: 'page', // 何ページ目かを示すパラメータのキー
  articleCount: 20, // 1ページあたりに表示させる記事の件数
  pagerMaxCount: 5 // ページ送りの最大数
}

ページャー実装のデモページ2-2

const pagerOptions = {
  paramKey: 'page', // 何ページ目かを示すパラメータのキー
  articleCount: 10, // 1ページあたりに表示させる記事の件数
  pagerMaxCount: 3 // ページ送りの最大数
}

ページャー実装のデモページ2-3

const pagerOptions = {
  paramKey: 'page', // 何ページ目かを示すパラメータのキー
  articleCount: 5, // 1ページあたりに表示させる記事の件数
  pagerMaxCount: 7 // ページャーの最大数
}

ページャー実装のデモページ2-4

const pagerOptions = {
  paramKey: 'page', // 何ページ目かを示すパラメータのキー
  articleCount: 10, // 1ページあたりに表示させる記事の件数
  pagerMaxCount: 4 // ページ送りの最大数
}

ページャー実装のデモページ2-5

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2024年12月
1234567
891011121314
15161718192021
22232425262728
293031