Vuetify 2のv-data-tableでshow-selectを使いつつtrタグにclassを設定したい

# 結論から

Vuetify 2.1.7で動作確認済みです。

```vue
<template>
  <v-data-table
    v-model="selected"
    :headers="headers"
    :items="items"
    item-key="id"
    show-select
  >
    <template v-slot:item="{ item, isSelected }">
      <tr :class="tableRowClass(item, isSelected)">
        <td>
          <v-simple-checkbox :value="isSelected" @input="toggleRow(item)" class="v-data-table__checkbox" hide-details />
        </td>
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.status }}</td>
      </tr>
    </template>
  </v-data-table>
</template>
<script>
export default {
  data () {
    return {
      headers: [
        { text: 'id', value: 'id', sortable: false },
        { text: 'name', value: 'name', sortable: false },
        { text: 'status', value: 'status', sortable: false }
      ],
      selected: [],
    }
  },
  methods: {
    toggleRow (item) {
      if (this.selected.includes(item)) {
        // item が含まれていたら除去する
        this.selected = this.selected.filter(v => v !== item)
      } else {
        // item を追加する
        this.selected.push(item)
      }
    },
    tableRowClass (item, isSelected) {
      let klasses = []
      if (item.status != 'active') klasses.push('grey') // status が active だったら tr に grey クラスを追加する
      if (isSelected) klasses.push('v-data-table__selected') // checkbox が選択されていたら tr に v-data-table__selected クラスを追加する
      return klasses.join(' ')
    }
  }
}
</script>
```

# 背景

Vuetify 2.x の v-data-table では 1.5.x に比べて設定できる slot が増え、テーブルの表現力が格段に上がりました。
1.5.x までは `<template slot="items" slot-scope="props">` と tbody 以下をまるっと書いていたものは `<template v-slot:body="{ items }"><tbody><tr v-for="item in items" :key="item.id">` や `<template v-slot:item="{ item }">` と書くことができたり、`<template v-slot:item.name="{ value }">` と個別の td 内のみを書くことができるようになっています。
ですが、今回 `show-select` (チェックボックスでrowを選択できる機能) を使いつつ items の個々の item (要は tr タグ) に class を動的に追加したい要件が出てきて、いざ設定しようとしたときに、ドキュメントにそれっぽい slot も存在しないし、ソースコードを見てもいい感じに設定できそうな書き方が思い付かず、どうやって追加したらいいものか結構悩みました。やっと解決できたので、覚書として記事に残します。

# 解決まで

最初は `vuetify 2 data-table row show-select checkbox` と Google で検索して出てきた
https://stackoverflow.com/questions/57671044/select-all-rows-of-a-vuetify-data-table-with-custom-table-body-implementation
↑この記事を参考に書き始めましたが、上手く行きませんでした。
以下に抜粋します。

```vue
<v-data-table v-model="selectedTasks" :headers="headers" :items="tasks" item-key="id" show-select>
  <template v-slot:body="{ items }">
    <tbody>
      <tr v-for="item in items" :key="item.id">
        <td>
          <v-checkbox v-model="selectedTasks" :value="item" style="margin:0px;padding:0px" hide-details />
        </td>
        <td>{{ item.text }}</td>
        <td>
          <v-btn text icon x-small>
            Edit
          </v-btn>
        </td>
      </tr>
    </tbody>
  </template>
</v-data-table>
...
<script>
data() {
  selectedTasks: []
}
</script>
```

上手く行かなかった点としては、

- v-checkboxの :value に `item` を指定しておいて、チェックボックスを押下すると、v-model の `selectedTasks` に要素が追加されます(ここまでは問題なし)。この後v-paginationなどでテーブルのitemsが変化すると、selectedTasksには要素が一つしか無いにも関わらず、表示されたitemsが全て選択された(チェックボックスがチェック済みになっている)状態になっていた。
- (気持ちの問題かもしれませんが、) style属性でmargin、paddingを設定するのがちょっと嫌だな…と。

これらの問題については、なぜそうなるのか詳しいところまで調べてはいません。

解決のポイントは

- `<template v-slot:item="{ item, isSelected }">`
    - `item` slot を使う。 
    - `body` だと row ごとの `isSelected` を取れない。
- `<v-simple-checkbox :value="isSelected" @input="toggleRow(item)" class="v-data-table__checkbox" hide-details />`
    - `v-checkbox` ではなくて `v-simple-checkbox` を使う。
    - `v-checkbox` だと、前後に (余計なタグやclassが挿入されてしまうため) margin や padding を調整しなければならない。
    - `v-simple-checkbox` なら `v-simple-checkbox` class のみの div タグが設定されて magin や padding の指定が不要。 `class="v-data-table__checkbox"` は Vuetify のソースコードでは付与しているので追加してみたが、特に表示上は有っても無くても変わらない模様。
    - `<v-checkbox v-model="selectedTasks" :value="item">` で上手くいきそうな気がするが、上記の items が全て選択された(意図しない)状態になる問題が発生する。
    - `v-simple-checkbox` の value に boolean を返す `isSelected` を指定して、 input イベントで selected に item を toggle する method を発火させる。

ざっくりとこんな感じです。

もしかしたら他に slot を上手く使うもっといい方法があるのかもしれませんので、詳しい方がいらっしゃったら是非コメントを頂きたいです m(_ _)m