単一ページアプリケーションにおけるフロントエンドページングの実装案について簡単に述べる
7423 ワード
概要
ページングは開発で最も一般的なニーズの一つです.ページングでは、バックエンドのデータベースページングが最も多く議論されています.これは、アプリケーションのパフォーマンスに関連し、ページングというニーズの核心でもあります.フロントエンドがしなければならないのは、バックエンドから返されたデータをページに表示することであり、仕事は簡単でこまごましたものとされています.単一ページアプリケーションでは、無限スクロール、前ページ&次ページ、ページ番号が最も一般的な中分割スキームがたくさんあります.本稿では,この3つのページング方式について述べる.
汎用
どのページング・スキームを使用しても、次のような一般的なニーズを処理する必要があります.
// url
// http://host/items?page=5 page=5 5
function parsePage() {
var searchString = window.location.search.substr(1).split('&').filter(v => v.indexOf('page') !== -1)[0];
var page = Number(searchString.split('=')[1]);
return isNaN(page) ? 1 : page;
}
// DOM
// generateItemView :: Object -> DOM Node
function generateItemView(object) { /* implementation */ }
// Node
function removeItems(node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
// Node
function insertItems(node, items) {
items.forEach(item => node.appendChild(generateItemView(item)));
}
次の例のコードでは、これらの関数が直接呼び出され、定義が繰り返されません.
無限スクロール
フロントエンドからでもバックエンドからでも、無限スクロールは最も簡単なページングスキームだと思います.バックエンドでは、
page
とlimit
に従って直接範囲を検出し、1つの配列をフロントエンドに返すだけで、他のスキームのように総数を検索する必要はありません.フロントエンドでは,バックエンドから返されたデータに直接つなぎ合わせればよいが,バックエンドが空の配列を返すと,最後のページに達したと考えられ,バックエンドに要求する必要はない.//
// GET /items?page=5
{ items: [...] }
//
function getItems(page) {
fetch(`/items?page=${page}`)
.then(res => res.json())
.then(res => {
if (res.items.length > 0) {
insertItems(
document.getElementById('container'),
res.items
);
} else {
alert('No more data');
}
});
}
無限スクロールは簡単で、ユーザー体験もいいですが、致命的な欠点があります.
前ページ&次ページ
このページング方式は無限スクロールに比べて少し複雑になります.最も重要なのは、バックエンドが合計クエリーを必要とし、現在のページ数に基づいて前のページまたは次のページをクエリーできるかどうかを計算することです.もちろん、この部分はバックエンドでもフロントエンドでも計算できます.
バックエンド計算
バックエンドで計算すると、バックエンドがしなければならないことがあります.
hasPrev
およびhasNext
hasPrev
およびhasNext
に基づいて、前ページ/次ページボタン//
// GET /items?page=5
{
// hasPrev hasNext ,
hasPrev: true,
hasNext: true,
items: [...]
}
//
function getItems(page) {
fetch(`/items?page=${page}`)
.then(res => res.json())
.then(res => {
res.hasPrev
? document.getElementById('prevButton').style.display = 'block'
: document.getElementById('prevButton').style.display = 'none';
res.hasNext
? document.getElementById('nextButton').style.display = 'block'
: document.getElementById('nextButton').style.display = 'none';
var container = document.getElementById('container');
removeItems(container);
insertItems(container, res.items);
});
}
このスキームは実装が簡単ですが、ページを分割するたびに総ページ数をクエリーし、リソースを浪費するのが欠点です.
フロントエンド計算
フロントエンド計算であれば、バックエンドが行うことは比較的簡単で、クエリの合計数のインタフェースを1つ提供すればよい.フロントエンドでは、現在のエンドデータが失われた場合(ユーザーがページをリフレッシュするなど)の処理案を考慮しながら、より多くのことをする必要があります.
hasPrev
およびhasNext
を計算し、前のページ/次のページボタン//
// GET /itemsCount
{ total: 100 }
// GET /items?page=5
{ items: [...] }
//
var total = 0;
var limit = 10;
window.onload = getItemsCount(getItems);
//
function getItemsCount(callback) {
fetch('/itemsCount')
.then(res => res.json())
.then(res => {
total = res.total;
callback.call(null, parsePage());
});
}
function getItems(page) {
fetch(`/items?page=${page}`)
.then(res => res.json())
.then(res => {
var hasPrev = page != 1;
var hasNext = page != Math.ceil(total / limit);
hasPrev
? document.getElementById('prevButton').style.display = 'block'
: document.getElementById('prevButton').style.display = 'none';
hasNext
? document.getElementById('nextButton').style.display = 'block'
: document.getElementById('nextButton').style.display = 'none';
var container = document.getElementById('container');
removeItems(container);
insertItems(container, res.items);
});
}
この案は後端を先端に振ることができて、先端の仕事はまたドラえもんになります!
ページ番号
最後にページ番号のページ分けについて話します.このシナリオは「前ページ&次ページ」のシナリオと似ていますが、現在のページと総数に基づいてページ番号を生成する必要がある点が異なります.ページ番号の生成はこのスキームで最も面倒なところです.簡単な例を挙げると、私たちのデータが50ページあると仮定すると、すべてのページ番号を表示することはできません.不連続なページ番号のセットを生成する必要があります.
次の形式でページを表示できます.
// ------------------------------
// -1
// DOM ,
// ------------------------------
// 1
[1, 2, 3, -1, 50]
// 3
[1, 2, 3, 4, 5, -1, 50]
// 25
[1, -1, 23, 24, 25, 26, 27, -1, 50]
// 48
[1, -1, 46, 47, 48, 49, 50]
// 50
[1, -1, 48, 49, 50]
ページ番号を生成する原則は、通常、次のとおりです.
var lastPage = Math.ceil(total / limit);
//
function genPages() {
if (lastPage <= 10) {
return Array(lastPage).fill().map((v, i) => i + 1);
}
// dynamicPages ,-1
var dynamicPages;
if (page === 1) {
dynamicPages = [2, 3, -1];
} else if (page === 2) {
dynamicPages = [2, 3, 4, -1];
} else if (page === 3) {
dynamicPages = [2, 3, 4, 5, -1];
} else if (page === lastPage - 2) {
dynamicPages = [-1, page - 2, page - 1, page, page + 1];
} else if (page === lastPage - 1) {
dynamicPages = [-1, page - 2, page - 1, page];
} else if (page === lastPage) {
dynamicPages = [-1, page - 2, page - 1];
} else {
dynamicPages = [-1, page - 2, page - 1, page, page + 1, page + 2, -1];
}
dynamicPages.unshift(1);
dynamicPages.push(lastPage);
return dynamicPages;
}
ダイナミックページ番号を生成する論理は、フロントエンドにおいてもバックエンドにおいてもあまり影響がなく、自分のニーズに合わせて選択できます.他の部分の詳細については、「前のページ&次のページ」と似ていますが、ここでは繰り返しません.
出典
http://scarletsky.github.io/2...
参考資料
https://github.com/xitu/gold-...