Vue.jsを使用したグリッドコンポーネントの作成
最新のグリッドUIコンポーネントがどのように見えるか、およびどの機能を提供する必要があるかについては、オンラインで多くの情報があります。 一般的な要件の1つは、グリッドコンポーネントを簡単に視覚化し、情報に基づいて操作できるようにすることです。
これはVue.jsを使用して簡単に実現できます。この記事では、次のユーザーエクスペリエンスで構成されるグリッドコンポーネントを構築します。
- 固定ヘッダーとスクロール可能なテーブル本体。
- テーブルページ間のページネーション。
- ページあたりの行数を変更する機能。
Vue.jsがインストールされていると仮定します。
以下のコードは本番環境に対応しておらず、教育目的でここに示されていることに注意してください。
コード
以下のコードは、公式のVue.jsドキュメントから抜粋した修正例です。
次のコードを使用して、新しい単一ファイルコンポーネント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
ファイルを作成し、データを追加します。
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が残りの作業を行います。