Vue.jsを使用したグリッドコンポーネントの作成
最新のグリッドUIコンポーネントがどのように見えるか、およびどの機能を提供する必要があるかについては、オンラインで多くの情報があります。 一般的な要件の1つは、グリッドコンポーネントを簡単に視覚化し、情報に基づいて操作できるようにすることです。
これはVue.jsを使用して簡単に実現できます。この記事では、次のユーザーエクスペリエンスで構成されるグリッドコンポーネントを構築します。
- 固定ヘッダーとスクロール可能なテーブル本体。
- テーブルページ間のページネーション。
- ページあたりの行数を変更する機能。
Vue.jsがインストールされていると仮定します。
以下のコードは本番環境に対応しておらず、教育目的でここに示されていることに注意してください。
コード
以下のコードは、公式のVue.jsドキュメントから抜粋した修正例です。
次のコードを使用して、新しい単一ファイルコンポーネントGrid.vueを作成します。
Grid.vue
<div class="wrapper"> <form id="search"> Search <input name="query" v-model="searchQuery"> </form> <div id="grid-template"> <div class="table-header-wrapper"> <table class="table-header"> <thead> <th v-for="key in columns" @click="sortBy(key)" :class="{ active: sortKey == key }" > {{ key | capitalize }} <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'"></span> </th> </thead> </table> </div> <div class="table-body-wrapper"> <table class="table-body"> <tbody> <tr v-for="entry in filteredData"> <td v-for="key in columns"> {{entry[key]}}</td> </tr> </tbody> </table> </div> </div> </div>
export default { name: "grid", props: { data: Array, columns: Array, }, data(){ return { searchQuery: '', sortKey: '', sortOrders: {}, } }, computed: { filteredData: function () { let sortKey = this.sortKey; let filterKey = this.searchQuery && this.searchQuery.toLowerCase(); let order = this.sortOrders[sortKey] || 1; let data = this.data; if (filterKey) { data = data.filter(function (row) { return Object.keys(row).some(function (key) { return String(row[key]).toLowerCase().indexOf(filterKey) > -1; }) }) } if (sortKey) { data = data.slice().sort(function (a, b) { a = a[sortKey]; b = b[sortKey]; return (a === b ? 0 : a > b ? 1 : -1) * order; }) } return data; }, }, filters: { capitalize: function (str) { return str.charAt(0).toUpperCase() + str.slice(1); } }, methods: { sortBy: function (key) { this.sortKey = key; this.sortOrders[key] = this.sortOrders[key] * -1 }, }, created(){ let sortOrders = {}; this.columns.forEach(function (key) { sortOrders[key] = 1; }) this.sortOrders = sortOrders; } }
body{ font-family: Helvetica Neue, Arial, sans-serif; font-size: 14px; color: #555; } table { border-spacing: 0; width: 100%; } th { background-color: #008f68; color: rgba(255,255,255,0.66); cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } td { border-bottom: 1px #008f68 solid; } th, td { min-width: 150px; padding: 10px 20px; } th.active { color: #fff; } th.active .arrow { opacity: 1; } .arrow { display: inline-block; vertical-align: middle; width: 0; height: 0; margin-left: 5px; opacity: 0.66; } .arrow.asc { border-left: 4px solid transparent; border-right: 4px solid transparent; border-bottom: 4px solid #FAE042; } .arrow.dsc { border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 4px solid #FAE042; } #grid-template { display: flex; display: -webkit-flex; flex-direction: column; -webkit-flex-direction: column; width: 600px; }
次に、このコンポーネントをApp.vue
ファイルにインポートし、データを追加します。
App.vue
import Grid from './Grid' export default { name: 'app', data() { return { gridData: [ { name: 'American alligator', location: 'Southeast United States' }, { name: 'Chinese alligator', location: 'Eastern China' }, { name: 'Spectacled caiman', location: 'Central & South America' }, { name: 'Broad-snouted caiman', location: 'South America' }, { name: 'Jacaré caiman', location: 'South America' }, { name: 'Black caiman', location: 'South America' }, ], gridColumns: ['name', 'location'], } }, components: { Grid } }
対応するデータを渡してコンポーネントを使用します。
<grid :data="gridData" :columns="gridColumns"></grid>
次に、このコンポーネントを、導入部で説明した追加機能で拡張してみましょう。
固定ヘッダー
記事TheHoly Grail:Pure CSS Scrolling Tables with Fixed Headers の手法を使用しており、マークアップはこの記事に従ってすでに設定されています。 テーブルの高さを定義し、テーブル本体をスクロール可能にします。
.wrapper{ height: 300px; } #grid-template > .table-body-wrapper { width: 100%; overflow-y: scroll; } #grid-template { height: 100%; } #grid-template > .table-body-wrapper { flex: 1; }
ページ付け
まず、ページあたりの行数と開始位置を定義しましょう。 このため、2つの新しいプロパティが追加されます。
startRow: 0, rowsPerPage: 10
現在のページ番号を表示するナビゲーションのマークアップを追加しましょう。
<div id="page-navigation"> <button>Back</button> <p>{{startRow / rowsPerPage + 1}} out of {{Math.ceil(filteredData.length / rowsPerPage)}}</p> <button>Next</button> </div>
ページ間で変更するには、ボタンのクリックイベントハンドラーを追加します。 戻るボタンの場合は@click=movePages(-1)
、次のボタンの場合は@click=movePages(1)
。
このメソッドは、ページの最初の行数をカウントします。
movePages: function(amount) { let newStartRow = this.startRow + (amount * this.rowsPerPage); if (newStartRow >= 0 && newStartRow < this.filteredData.length) { this.startRow = newStartRow; } }
次に、現在のページの行をフィルタリングして返す計算プロパティを追加します。
dataPerPage: function() { return this.filteredData.filter((item, index) => index >= this.startRow && index < (this.startRow + this.rowsPerPage)) }
ページ間を移動できるため、更新されたデータを表示する必要があります。 .table-body
をfilteredDataからdataPerPageに変更します。
<tr v-for="entry in dataPerPage"> <td v-for="key in columns"> {{entry[key]}}</td> </tr>
長さの選択
行数を設定できるようにするには、v-modelがrowsPerPageプロパティと等しい単純な選択を追加します。
オプションについては、pageSizeMenuプロパティを数値の配列に設定します。
pageSizeMenu: [10, 20, 50, 100]
<select v-model="rowsPerPage"> <option v-for="pageSize in pageSizeMenu" :value="pageSize">{{pageSize}}</option> </select>
そして、これはあなたがページごとの行数を変更する能力を持つために必要なすべてです。 双方向のデータバインディングのおかげで、Vueが残りの作業を行います。