以前に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 // ページ送りの最大数
}
コメントが承認されるまで時間がかかります。