Vue.js/リストを改良した
ページングした
前回、複数ある項目をリスト表示して、件数を数えて、絞り込み機能をつけました。絞り込まれたリスト(filteredRows)が現在の表示対象です。全部で6件あるデータ(rows - filteredRows)を2件ずつ表示するページング機能(rows - filteredRows - pagedRows)を作ってみましょう。
const app = Vue.createApp({
data() {
return {
rows: [ .. ],
page: 0,
per: 10,
...
}
},
computed: {
filteredRows() { .. },
pagedRow() {
return this.filteredRows.slice(this.page*this.per,this.page*this.per+this.per);
},
}
});
app.mount('#list');
data部にページングされた何ページ目を表示されるかを表す page と1ページにいくつデータを表示するかを表す per という項目を足しました。pageは0始まりなので初期値は0です。6件のデータを1ページ2件、3ページに分けるのでperは2です。
computed部のpagedRowはfilteredRowsから選択されたページ(page)のデータを抜き出して返します。
これで最初の1ページ目が表示されるようになりました・・・が、次のページに移動できません。pageデータを変更する操作部を作りましょう。
操作部
const app = Vue.createApp({
data() { .. },
computed: { .. },
methods: {
pageList() {
const n = this.pageNumber()+1;
const c = this.page+1;
let list = [],to = false;
for (let x=1;x<=n;x++) {
if (
x === 1 ||
x === n ||
(c <= 4 && x <= 5) ||
(c > 4 && c <= n - 4 && (c - 1 <= x && x <= c + 1)) ||
(c > n - 4 && x >= n - 4)
) {
list.push(x);
to = false;
} else if (!to) {
list.push(-1);
to = true;
}
}
return list;
},
pageNumber() {
return Math.floor((this.filteredRows.length-1)/this.per);
},
prevPage() {
if (this.page>0) this.movePage(this.page-1);
},
nextPage() {
if (this.page+1<=this.pageNumber()) this.movePage(this.page+1);
},
movePage(p) {
this.page = p;
},
}
});
app.mount('#list');
methods部にpageListというのを用意しました。これを呼び出した場所にページ番号の選択肢の配列を返します。番号が多すぎて画面がぐちゃぐちゃにならないように、よくある中間を間引く処理もついています。
pageNumberはページの数を返すメソッドで、指定のページに移動するのがmovePage、前後のページに移動するのがそれぞれprevPage、nextPageです。page値を書き換えるだけで描画してくれるので楽ちん!
<div class="paging">
<span class="prev" v-if="page != 0" @click="prevPage">←</span>
<span class="numbers">
<span v-for="p in pageList()" :class="pageClass(p)" @click="movePage(p-1)">{{ p==-1 ? '…' : p }}</span>
</span>
<span class="next" v-if="page != pageNumber()" @click="nextPage">→</span>
</div>
HTML側はこんな感じにしてみました。番号列の前後にはクリックすると一つ前のページ、一つ後ろのページに移動する要素も置いてあります。
computedでデータを整形して、操作するUIをつけてあげる・・・こういうのを役割に応じていじる部分が固まっているのが、製作を楽にしてくれるんでしょうね。保守性はまだわかんないですけど。