10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DataTable: Vuetify3 の新コンポーネント (labs) を試す

Last updated at Posted at 2023-07-14

このページは、下記ページへ移行しました。参考までに、記事の内容はのことしておきます。

内容

DataTable は表形式のデータを表示するコンポーネントです。v-table よりも機能が豊富です。

前提

Vuetify のバージョンは 3.4.6 で試しています。バージョンが上がると仕様は変更されるかもしれません。

公式

基本

データをテーブル形式で表示します。表示する行の数を指定すると、データ数が指定した数より多い時は、自動的にページ送り機能がつきます。

image.png

.vue
<template>
  <v-container>
    <p class="text-h3">DataTable</p>
    <v-data-table
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="pref"
      :items-per-page-options="pages"
      items-per-page-text="表示行数"
      class="elevation-1"
    ></v-data-table>
  </v-container>
</template>

<script>
export default {
  data () {
    return {

      itemsPerPage: 5,
      pages: [
        {value: 5, title: '5'},
        {value: 10, title: '10'},
        {value: 20, title: '20'},
        {value: -1, title: '$vuetify.dataFooter.itemsPerPageAll'}
      ],
      headers: [
        {
          title: '番号',
          align: 'end',
          sortable: false,
          key: 'no',
        },
        { title: '都道府県名', align: 'start', key: 'pref_jp' },
        { title: '英語名', align: 'start', key: 'pref_en' },
        { title: '面積(km2)', align: 'end', key: 'area' },
        { title: '人口(千人)', align: 'end', key: 'population' },
      ],
      pref: [
        {no: 1,pref_jp: "北海道",pref_en: "Hokkaido",area: 83457,population: 5400},
        {no: 2,pref_jp: "青森",pref_en: "Aomori",area: 9645,population: 1321},
        {no: 3,pref_jp: "岩手",pref_en: "Iwate",area: 15279,population: 1284},
        {no: 4,pref_jp: "宮城",pref_en: "Miyagi",area: 6862,population: 2328},
        {no: 5,pref_jp: "秋田",pref_en: "Akita",area: 11636,population: 1037},
        {no: 6,pref_jp: "山形",pref_en: "Yamagata",area: 6652,population: 1131},
        {no: 7,pref_jp: "福島",pref_en: "Fukushima",area: 13783,population: 1935},
        {no: 8,pref_jp: "茨城",pref_en: "Ibaraki",area: 6096,population: 2919},
        {no: 9,pref_jp: "栃木",pref_en: "Tochigi",area: 6408,population: 1980},
        {no: 10,pref_jp: "群馬",pref_en: "Gumma",area: 6362,population: 1976},
        {no: 11,pref_jp: "埼玉",pref_en: "Saitama",area: 3768,population: 7239},
        {no: 12,pref_jp: "千葉",pref_en: "Chiba",area: 5082,population: 6197},
        {no: 13,pref_jp: "東京",pref_en: "Tokyo",area: 2104,population: 13390},
        {no: 14,pref_jp: "神奈川",pref_en: "Kanagawa",area: 2416,population: 9096},
        {no: 15,pref_jp: "新潟",pref_en: "Niigata",area: 10364,population: 2313},
        {no: 16,pref_jp: "富山",pref_en: "Toyama",area: 2046,population: 1070},
        {no: 17,pref_jp: "石川",pref_en: "Ishikawa",area: 4186,population: 1156},
        {no: 18,pref_jp: "福井",pref_en: "Fukui",area: 4190,population: 790},
        {no: 19,pref_jp: "山梨",pref_en: "Yamanashi",area: 4201,population: 841},
        {no: 20,pref_jp: "長野",pref_en: "Nagano",area: 13105,population: 2109},
        {no: 21,pref_jp: "岐阜",pref_en: "Gifu",area: 9768,population: 2041},
        {no: 22,pref_jp: "静岡",pref_en: "Shizuoka",area: 7255,population: 3705},
        {no: 23,pref_jp: "愛知",pref_en: "Aichi",area: 5116,population: 7455},
        {no: 24,pref_jp: "三重",pref_en: "Mie",area: 5762,population: 1825},
        {no: 25,pref_jp: "滋賀",pref_en: "Shiga",area: 3767,population: 1416},
        {no: 26,pref_jp: "京都",pref_en: "Kyoto",area: 4613,population: 2610},
        {no: 27,pref_jp: "大阪",pref_en: "Osaka",area: 1901,population: 8836},
        {no: 28,pref_jp: "兵庫",pref_en: "Hyogo",area: 8396,population: 5541},
        {no: 29,pref_jp: "奈良",pref_en: "Nara",area: 3691,population: 1376},
        {no: 30,pref_jp: "和歌山",pref_en: "Wakayama",area: 4726,population: 971},
        {no: 31,pref_jp: "鳥取",pref_en: "Tottori",area: 3507,population: 574},
        {no: 32,pref_jp: "島根",pref_en: "Shimane",area: 6708,population: 697},
        {no: 33,pref_jp: "岡山",pref_en: "Okayama",area: 7010,population: 1924},
        {no: 34,pref_jp: "広島",pref_en: "Hiroshima",area: 8480,population: 2833},
        {no: 35,pref_jp: "山口",pref_en: "Yamaguchi",area: 6114,population: 1408},
        {no: 36,pref_jp: "徳島",pref_en: "Tokushima",area: 4147,population: 764},
        {no: 37,pref_jp: "香川",pref_en: "Kagawa",area: 1862,population: 981},
        {no: 38,pref_jp: "愛媛",pref_en: "Ehime",area: 5679,population: 1395},
        {no: 39,pref_jp: "高知",pref_en: "Kochi",area: 7105,population: 738},
        {no: 40,pref_jp: "福岡",pref_en: "Fukuoka",area: 4847,population: 5091},
        {no: 41,pref_jp: "佐賀",pref_en: "Saga",area: 2440,population: 835},
        {no: 42,pref_jp: "長崎",pref_en: "Nagasaki",area: 4106,population: 1386},
        {no: 43,pref_jp: "熊本",pref_en: "Kumamoto",area: 7268,population: 1794},
        {no: 44,pref_jp: "大分",pref_en: "Oita",area: 5100,population: 1171},
        {no: 45,pref_jp: "宮崎",pref_en: "Miyazaki",area: 6795,population: 1114},
        {no: 46,pref_jp: "鹿児島",pref_en: "Kagoshima",area: 9045,population: 1668},
        {no: 47,pref_jp: "沖縄",pref_en: "Okinawa",area: 2277,population: 1421}
      ],
    }
  }
}
</script>
  • v-model:items-per-page: 1ページ内に表示するデータの行数を指定します。
  • headers: テーブルのヘッダ(項目名など)のデータを指定します。
  • item: データ本体を指定します。headers と項目数が一致しないと、表示が崩れます。
  • items-per-page-text: 表示する行数を指定するメニューの左側に表示される文字列です。デフォルトでは item per pages になります。
  • items-per-page-options: 表示する行数を選択するメニューの選択肢のリストを指定します。デフォルトでは 10, 20, 50, 100, ALL という選択肢のメニューになります。

class="elevation-1"を指定しないと、テーブルと背景の境(枠)がなくなります。class="border" でも枠はつきます。

応用

項目ソート

DataTable はデフォルトで項目ごとのソート機能がついています。テーブルの最上段の項目名を押すことでソートが実行されます。ソートは、項目名を押すたびに、昇順、降順、先頭の項目の番号順、という順序でソート順序が入れ替わります。

面積で降順ソートすると下図のようになります。

image.png

multi-sort prop を使うと、複数項目によるソートが可能になります。ソートを禁止したい場合は、近視したいレツの headersortable: false を追加します。上の例では key: no の列に対するソートを禁止しています。

項目の上下の空白を指定: density

density prop を入れると各行の上下のスペースの空き具合を指定できます。density="compact" とすると、かなり詰まった状態になります。comfortable だとやや詰まりになります。

image.png

.vue
<template>
  <v-container>
    <v-data-table
      density="compact"
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="pref"
      :items-per-page-options="pages"
      items-per-page-text="表示行数"
      class="elevation-1"
    ></v-data-table>
  </v-container>
</template>

選択: show-select

show-select prop を使うと、行を選択するチェックボックスがつきます。デフォルトでは複数選択が許可されています。select-strategy="single" とすると複数選択を禁止できます。

image.png

<template>
  <v-container>
    <v-data-table
      density="compact"
      show-select
      v-model="selected"
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="pref"
      item-value="no"
      :items-per-page-options="pages"
      items-per-page-text="表示行数"
      class="elevation-1"
    ></v-data-table>
    <div>
      {{ selected }}
    </div>
  </v-container>
</template>

show-select を指定するときは、同時に item-value でデータを区別するためにつかう key を指定します。これを指定しないと、どのチェックボックスを選択しても、全部のデータが選択されます。

選択したデータは v-model で指定した変数に配列として入ります。配列に入るのは、選択した行の item-value で指定した列の値です。

行にボタンを追加する: v-slot:item

v-slot:item を使うことで、各行の中にボタンやアイコンなどを表示する列を追加できます。

image.png

<template>
  <v-container>
    <v-data-table
      density="compact"
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="pref"
      item-value="no"
      :items-per-page-options="pages"
      items-per-page-text="表示行数"
      class="elevation-1"

    >
      <template v-slot:item.actions="{ item }">
        <v-icon
          size="small"
          @click="deleteItem(item.raw)"
        >
          mdi-delete
        </v-icon>
      </template>

    </v-data-table>
  </v-container>
</template>

<script>
export default {
  methods: {
    deleteItem(item){
      alert( item.no + "番のデータを削除します");
    }
  },
  data () {
    return {

      itemsPerPage: 5,
      selected: [],
      pages: [
        {value: 5, title: '5'},
        {value: 10, title: '10'},
        {value: 20, title: '20'},
        {value: -1, title: '$vuetify.dataFooter.itemsPerPageAll'}
      ],
      headers: [
        { title: '番号', align: 'end', sortable: false, key: 'no' },
        { title: '都道府県名', align: 'start', key: 'pref_jp' },
        { title: '英語名', align: 'start', key: 'pref_en' },
        { title: '面積(km2)', align: 'end', key: 'area' },
        { title: '人口(千人)', align: 'end', key: 'population' },
        { title: '操作', align: 'end', key: 'actions' },
      ],
      pref: [ // 省略
      ],
    }
  }
}
</script>

上の例では v-slot:item.actions としていますが、この場合は headers に key: 'actions' という項目を持つデータ(項目)を追加しておく必要があります。headers の中に  v-slot:item.xxxxxxxx と一致する key をもつ項目がない場合は、v-slot で指定したボタンなどは表示されません。

行に他の項目から計算した項目を追加: v-slot:item

ボタンを追加したときと同じ方法で、行に表示する項目を追加できます。下の図では人口密度の項目を都度計算して表示させています。

image.png

<template>
  <v-container>
    <v-data-table
      density="compact"
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="pref"
      item-value="no"
      :items-per-page-options="pages"
      items-per-page-text="表示行数"
      class="elevation-1"
    >
      <template v-slot:item.density="{ item }">
          {{ (item.columns.population*1000 / item.columns.area).toFixed(2) }}
      </template>
    </v-data-table>

  </v-container>
</template>

<script>
export default {
  methods: {
    deleteItem(item){
      alert( item.no + "番のデータを削除します");
    }
  },
  data () {
    return {
      search: ``,
      itemsPerPage: 5,
      selected: [],
      pages: [
        {value: 5, title: '5'},
        {value: 10, title: '10'},
        {value: 20, title: '20'},
        {value: -1, title: '$vuetify.dataFooter.itemsPerPageAll'}
      ],
      headers: [
        { title: '番号', align: 'end', sortable: false, key: 'no' },
        { title: '都道府県名', align: 'start', key: 'pref_jp' },
        { title: '英語名', align: 'start', key: 'pref_en' },
        { title: '面積(km2)', align: 'end', key: 'area' },
        { title: '人口(千人)', align: 'end', key: 'population' },
        { title: '人口密度', align: 'end', key: 'density', sortable: false },
      ],
pref: [ // 省略
      ],
    }
  }
}
</script>

この方法で追加した項目は、ソート機能が使えません(自力でソート機能を実装しない限り)。上の例では sortable: false を指定して、人口密度でのソートを禁止しています。

検索

search prop で文字列を指定すると、その文字列を含むデータだけを表示します。

image.png

<template>
  <v-container>
    <v-text-field
        v-model="search"
        append-icon="mdi-magnify"
        label="検索"
        single-line
        hide-details
      ></v-text-field>

    <v-data-table
      density="compact"
      v-model:items-per-page="itemsPerPage"
      :headers="headers"
      :items="pref"
      item-value="no"
      :search="search"
      :items-per-page-options="pages"
      items-per-page-text="表示行数"
      class="elevation-1"
    >
    </v-data-table>
  </v-container>
</template>

デフォルトでは、すべての列のデータを対象にフィルタ(検索)します。特定の列のデータを使ってフィルタしたいときは、フィルタする関数を自力で書く必要があります。詳しくは下記を参照してください。

サーバのデータを順次読み込む

サーバにあるデータの一部だけ表示しておいて、ページをめくっていったりスクロールさせていくと、残りが読み込まれて表示される、みたいなこともできます。

サーバがないとサンプルがかけないので、ここでは例示はしません。詳しくは下記を参照してください。

10
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?