以前に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 // ページ送りの最大数 }
const pagerOptions = { paramKey: 'page', // 何ページ目かを示すパラメータのキー articleCount: 20, // 1ページあたりに表示させる記事の件数 pagerMaxCount: 5 // ページ送りの最大数 }
const pagerOptions = { paramKey: 'page', // 何ページ目かを示すパラメータのキー articleCount: 10, // 1ページあたりに表示させる記事の件数 pagerMaxCount: 3 // ページ送りの最大数 }
const pagerOptions = { paramKey: 'page', // 何ページ目かを示すパラメータのキー articleCount: 5, // 1ページあたりに表示させる記事の件数 pagerMaxCount: 7 // ページャーの最大数 }
const pagerOptions = { paramKey: 'page', // 何ページ目かを示すパラメータのキー articleCount: 10, // 1ページあたりに表示させる記事の件数 pagerMaxCount: 4 // ページ送りの最大数 }
コメントが承認されるまで時間がかかります。