はじめに
こんにちは、フロントエンドエンジニアのraraya99です。 近年のフロントエンド開発は、数多くのライブラリやフレームワークを活用することで、効率的かつ高品質なプロジェクト制作が可能となっています。 前回の記事でVueUseについて紹介させていただきました。
今回はコンポーネントフレームワーク Vuetify の v-data-table に焦点を当てます。私たちのプロジェクトでは、Vuetify の様々なコンポーネントを直接使用せず、独自の UI デザインを適用するためにラップして活用しています。そのため、Vuetify の持つ柔軟性を活かしつつ、プロジェクト固有のデザイン要件に対応しています。(今回の記事では便宜上、ラップせず直接使用します。)
v-data-table は、データの整理・表示に優れた、柔軟なコンポーネントです。基本機能だけでも美しいデータテーブルを簡単に作成できますが、その中でも 「複数行ヘッダー」 に注目します。複雑なデータ表示に適したこの機能を活用することで、さらに読みやすく、直感的なデザインが可能になります。vuetifyにはv-data-tableと似たv-tableというコンポーネントも存在しますが今回は触れません。(下記で比較だけいたします)
v-data-tableとv-tableの比較
Vuetify には、v-data-table と似た v-table というコンポーネントも存在します。 どちらを選ぶかは、プロジェクトの要件によって決まります。
v-table: 静的なテーブルの表示に適しており、軽量でシンプルな実装が可能です。 v-data-table: 動的なテーブルの操作に適しており、ソート・検索・ページネーション・グループ化・行選択などの機能を備えています。
なぜ複数行ヘッダーに注目したのか?
業務の中で複雑なデータを扱う際、ヘッダーの情報量が多く2行から3行に増やして整理したいという課題がありました。 試してみたところ簡単に実装できたため、この記事では以下の流れで紹介します。
- v-data-table の基本的な使い方
- 複数行ヘッダーの構築方法
- さらに複雑なヘッダー構造の実現例
- その他の便利な機能の活用(おまけ)
v-data-tableの基本的な使い方
まずは最小構成の1行ヘッダーからスタートします。
ページネーションも自動で追加され、デフォルトで高い完成度を持っています。
ヘッダーを2行にする方法
複数行ヘッダーを実現するには、children プロパティを利用します。親ヘッダーの下に子ヘッダーを定義することで、階層構造を作成できます。
children プロパティを使うだけで、見やすく整理された2行ヘッダーを簡単に作成できます。 「特徴」という親ヘッダーの下に「種」と「タイプ」、「生息地」が配置され、構造が明確になります。
中略 const headers = [ { title: '基本情報', children: [ { title: '名前', value: 'name' }, { title: '重さ (kg)', value: 'weight' }, ], }, { title: '特徴', children: [ { title: '種', value: 'species' }, { title: 'タイプ', value: 'type' }, { title: '生息地', value: 'habitat' }, ], }, ] const items = [ { name: 'ピカチュウ', weight: 6, species: 'ネズミポケモン', type: 'でんき', habitat: '森', }, { 中略
さらに複雑なヘッダー構成
ヘッダーを3行以上に拡張することも簡単です。children をさらにネストすることで、より深い階層構造を作成できます。
この柔軟性は、公式の型定義からも確認できます。children プロパティが 再帰的に DataTableHeader 型を参照 しています。
type DataTableHeader<T = Record<string, any>> = { key?: 'data-table-group' | 'data-table-select' | 'data-table-expand' | (string & {}); value?: SelectItemKey<T>; title?: string; fixed?: boolean; align?: 'start' | 'end' | 'center'; width?: number | string; minWidth?: string; maxWidth?: string; nowrap?: boolean; headerProps?: Record<string, any>; cellProps?: HeaderCellProps; sortable?: boolean; sort?: DataTableCompareFunction; sortRaw?: DataTableCompareFunction; filter?: FilterFunction; mobile?: boolean; children?: DataTableHeader<T>[]; };
その他の便利な機能
予想に反してさくっと3行のヘッダーができてしまったため、現時点では弊社サービス Re:lation で採用していないものの、今後活用できそうなv-data-tableのcell-props を紹介します。
cell-props を使うと、セル単位でスタイルを動的に変更でき、条件に応じたカスタマイズが柔軟に行えます。
実装例
getCellProps を利用して、特定の条件に基づいてセルや列全体にスタイルを適用します。
<script setup lang="ts"> const headers = [ { title: 'Name', value: 'name' }, { title: 'Price', value: 'price' }, ]; const items = [ { name: 'りんご', price: 120 }, { name: 'キウイ', price: 40 }, { name: 'バナナ', price: 80 }, { name: 'ぶどう', price: 100 }, { name: 'さくらんぼ', price: 150 }, ] // セルのプロパティを取得 const getCellProps = (cell: any) => { const classes: string[] = []; const styles: Record<string, string> = {}; // 列のスタイルを指定 if (cell.column.key === 'name') { classes.push('name-column'); } // セルのスタイルを指定 if (cell.column.value === 'price') { if (cell.value >= 150) { classes.push('high-price'); styles.color = 'red'; styles.fontWeight = 'bold'; } else if (cell.value >= 100) { classes.push('high-price'); } } return { class: classes.join(' '), style: Object.keys(styles).length ? styles : undefined, }; }; </script> <template> <v-data-table :items="items" :headers="headers" :cell-props="getCellProps" /> </template> <style> .name-column { font-weight: bold; } .high-price { background-color: #ffeeee; } </style>
まとめ
v-data-table は、ヘッダーを簡単に複数行に拡張できる柔軟性や、cell-props を使った動的カスタマイズが魅力です。
さらに、標準搭載のソートや検索機能に加え、使い込むほど便利な機能が発掘できる奥深さがあります。
他にも便利な機能やコンポーネントがありましたら、ぜひ教えていただけると嬉しいです!