ホーム > Laravel > Vuetifyを使って綺麗な表を作る方法【v-data-table】
Laravel

Vuetifyを使って綺麗な表を作る方法【v-data-table】

いつもご利用ありがとうございます。
この記事には広告が掲載されており、その広告費によって運営しています。

Vuetify を使って綺麗な表(table)を作る方法についてまとめました。

v-data-table とは?

Vuetify には、簡単に、綺麗で機能性に優れた表を作ることが可能なコンポーネントが用意されています。

それがv-data-tableです。

Data tables - Vuetify

機能性とは?

  1. ページネーション
  2. ソート(並び替え)
  3. フィルター

こういった機能を簡単につけることができます。

自作しようと思うと大変ですよね。

基本形

<script setup>
  import { Head, Link } from "@inertiajs/vue3"

  const headers = [
    {
      title: "タイトル",
      value: "title",
    },

    { title: "カテゴリー", value: "category" },

    { title: "内容", value: "content" },
  ]
  const items = [
    {
      title: "タイトル1",
      category: "カテゴリー1",
      content: "内容ないよう内容ないよう内容ないよう内容ないよう内容ないよう1",
    },
    {
      title: "タイトル2",
      category: "カテゴリー2",
      content: "内容ないよう内容ないよう内容ないよう内容ないよう内容ないよう2",
    },
    {
      title: "タイトル1",
      category: "カテゴリー1",
      content: "内容ないよう内容ないよう内容ないよう内容ないよう内容ないよう2",
    },
  ]
</script>

<template>
  <div>
    <head title="Welcome" />
    <v-data-table
      :headers="headers"
      :items="items"
      item-key="name"
      items-per-page="5"
    ></v-data-table>
  </div>
</template>

headers で表の見出しを作る

titleに表に表示したいテキスト、valueにプロパティを入れます。

const headers = [
  {
    title: "タイトル",
    value: "title",
  },

  { title: "カテゴリー", value: "category" },

  { title: "内容", value: "content" },
]

items で内容を表示する

headers の value で指定した、プロパティがその列に表示されます。

const items = [
  {
    title: "タイトル1",
    category: "カテゴリー1",
    content: "内容ないよう内容ないよう内容ないよう内容ないよう内容ないよう1",
  },
  {
    title: "タイトル2",
    category: "カテゴリー2",
    content: "内容ないよう内容ないよう内容ないよう内容ないよう内容ないよう2",
  },
  {
    title: "タイトル1",
    category: "カテゴリー1",
    content: "内容ないよう内容ないよう内容ないよう内容ないよう内容ないよう2",
  },
]

コンポーネントに props を渡す

さきほどの headers や items を props で渡します。

<v-data-table
  :headers="headers"
  :items="items"
  item-key="name"
  items-per-page="5"
></v-data-table>

以上が基本形となります。

API などからデータを受け取った場合

変数にデータを格納し、props で渡せば表示できます。

<script setup>
  import { Head } from "@inertiajs/vue3"
  import { ref, onMounted } from "vue"
  import axios from "axios"

  const posts = ref([])

  const headers = [
    { title: "タイトル", value: "title" },
    { title: "カテゴリー", value: "category" },
    { title: "内容", value: "content" },
  ]

  const fetchPosts = async () => {
    try {
      const response = await axios.get("/api/posts") // APIエンドポイントを適宜変更
      posts.value = response.data
    } catch (error) {
      console.error("Error fetching posts:", error)
    }
  }

  onMounted(fetchPosts)
</script>

<template>
  <div>
    <head title="Welcome" />
    <v-data-table
      :headers="headers"
      :items="posts"
      item-key="id"
      items-per-page="5"
    ></v-data-table>
  </div>
</template>

itemsが props 名でpostsが変数名です。

:items="posts"

1ページに表示するデータ量を変更する方法

items-per-pageで数字を指定します。

<v-data-table
  :headers="headers"
  :items="posts"
  item-key="name"
  items-per-page="100"
></v-data-table>

ソート(並び替え)を付ける方法

headerssortableを付けると昇順、降順を選択する矢印が出ます。

const headers = [
  {
    title: "タイトル",
    value: "title",
  },

  { title: "カテゴリー", value: "category", sortable: true },

  { title: "内容", value: "content" },
]

初期の並び替えをしたい場合は、sort-byに指定します。

const sortBy = [{ key: 'category', order: 'desc' }]

<v-data-table
  :headers="headers"
  :items="posts"
  item-key="name"
  items-per-page="5"
  :sort-by="sortBy"
></v-data-table>

テキストで絞り込みしたい場合

searchという props に渡せば良いです。

入力欄を作って、v-model で関連する変数を指定。それをsearchに渡します。

<script setup>
  import { ref } from "vue"

  const searchWord = ref("") //追記

  //これまで書いてきたheadersなどは省略してます
</script>

<v-text-field v-model="searchWord" label="絞り込み"></v-text-field> //追記
<v-data-table
  :headers="headers"
  :items="posts"
  item-key="name"
  items-per-page="5"
  :search="searchWord"
></v-data-table>

データ量が多すぎる場合

これまでのやり方は、データを一括で最初に取得し、それを表示するやり方でした。

大抵の場合、これで大丈夫でしょう。

ただ、このやり方だとデータ量が多くなると重くなってしまう可能性があり、それを改善する方法として

「サーバーサイドテーブル」と「仮想テーブル」が用意されています。

簡単なのは仮想テーブル

仮想テーブルはこれまでのやり方とほとんど変わらない方法で、行の一部分のみをレンダリングしてくれます。

なので、大きなデータを扱うことができます。

ただ、このやり方では、ページネーションを使うことができません。

v-data-table-virtualコンポーネントに変えるだけで使えます。

<script setup>
  import { ref, onMounted } from "vue"
  defineProps({
    posts: Array,
  })

  const headers = [
    {
      title: "タイトル",
      value: "title",
    },

    { title: "カテゴリー", value: "category", sortable: true },

    { title: "内容", value: "content" },
  ]

  const searchWord = ref("")
</script>

<template>
  <div>
    <v-text-field v-model="searchWord" label="絞り込み"></v-text-field>
    <v-data-table-virtual
      :headers="headers"
      :items="posts"
      item-key="name"
      :search="searchWord"
    ></v-data-table-virtual>
  </div>
</template>

API を作り込まないといけないが、色々できるサーバーサイドテーブル

表の機能を触った際のイベントでサーバーと通信をして、新しいデータを取得しなおす形になります。

当然、サーバーが返すデータを作るのは我々なので、なかなか大変な作業となります。

ここでは大体の方針だけ紹介する形で許してください。

v-data-table-serverコンポーネントを使います。

<script setup>
  import { ref, onMounted } from "vue"
  defineProps({
    posts: Array,
  })

  const headers = [
    {
      title: "タイトル",
      value: "title",
    },

    { title: "カテゴリー", value: "category", sortable: true },

    { title: "内容", value: "content" },
  ]

  const loadItems = ({ page, itemsPerPage, sortBy }) => {
    console.log(page)
    console.log(itemsPerPage)
    console.log(sortBy)
  }
</script>

<template>
  <div>
    <v-data-table-server
      :items="posts"
      :headers="headers"
      @update:options="loadItems"
    ></v-data-table-server>
  </div>
</template>

表の操作が行われた時、ページ数やソートされた情報が伝わり、それを元にサーバーと Fetch します。

イメージとしてはこんな感じで、その情報に応じてサーバーからデータを返します。

const posts = ref([])

const loadItems = ({ page, itemsPerPage, sortBy }) => {
  console.log(page)
  console.log(itemsPerPage)
  const { data } = await axios.get('https://localhost/api/posts',{
    params: {
      page: page,
      per_page: itemsPerPage,
    }
  })
  posts.value = data
}

以上、v-data-tableについてやってみました。

さくっと表を作りたい時に便利だと思います。

誰かの参考になれば幸いです。

フィードバックのお願い
この記事のフィードバックがありましたらYoutubeの適当な動画にコメントしていただいたり、お問い合わせからご連絡ください。