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をつけてあげる・・・こういうのを役割に応じていじる部分が固まっているのが、製作を楽にしてくれるんでしょうね。保守性はまだわかんないですけど。