VuetifyのTableで列の横幅を固定にする方法

# はじめに
VuetifyのTableで列の横幅を全て固定とする方法を調べたので、記事にします。
使用しているコンポーネントは`v-data-table-server`ですが、他のテーブルコンポーネントでも使えるかもしれないです。

# サンプルコード

https://play.vuetifyjs.com/#eNqtWHtv2zYQ/yoHY4Pl1VL8biI42bp03bIMXf4oNgxJgNIS7QjVCxTl1DP83Xt8iZItw0GR/CP67nj34z14x9xvOwULzt7lubcuacfvzDlN8phwevWQAszXbkg4cTlZxNQtKFtTJugAazfJQhr7EcoXbk6Zm5MVvXzoSMIdZXf486GjhP0nSkLKCmTrVcWR4khXum/ErybPjWm64k8owjNO4qZEnJEwSlfI1KuKU1DCArFLLQxdqHTXJC4F1JQkFcRfyhxPSv0s51GWCkRCY9NawTex2LeF5yjkTz5It/wr1rBTUlfzsxaXoS/nZzXHzouARTmHgvIyl46OkjxjHLbA6LIPz4QHqBKWLEugi4HpPqRCKkBkvG71Usg73W7PcrWDNeteQd+qDwCPeEx96L6nBULj4AwHgxXiYGt0Xq/bN3IkjlYpyhWcMG7JBYIU1n1YkrigFf0L3aCw8KeV1T7qooX8qyHv9PcA0DWJMxbRwu5XOoMDuoFG0/B7jX0gePL6cZWtJakd9RXMXBO2KNoMBYLxqqbuWMZplLYZyxXrVc3dsAxt/XhgK0L69xt6xDQWX5n+juI4Pbi8MkntycrVe5yUPv8jf0MWh3IlZSuw9Xr4JO4OUzNmo8doWAbUcYoy6curoanAqJCQcV9OWEFvUu4IUU9S+zAcyOJTfwwLmqWA+uANOFHxkXx0pFwPfoYB+EpVtWHXB7vblrU6Jhr8/MN2H/4u//r5SHCiJKFhJC4x4Kxy0058tGPVcUJV++KK2L8eRAWL+mDZ/zSF/7JVWa9+U4s+DKcXFRWrxodZTQhz24fRpKLoBPTBkkSeiBw4mmgayJ80jjewoKSWVRbF+O20iWKwj+KiBYUV0igGp1DcRvy2fjVYBNPheRPB6MARM4uxgvB2H8LsFITfgphErA3CaDZqQhgexmJ8CMEKaQhvT0H4HTsEZQuGCdkajKlVeQTHxCZNhWPsWaLJipPeuAkoBAgkgYKk4XMUPLV6Zmz9LBFZSxpQTcAmqWe99dI0/SuL4yjP8la/XOzFZ+BZgklTm0XH03R0CsV1mQfkS60D10AM9ipl7Nmjm0R9mTPOT8H4I0vpJsiSRRuQyWCvYMaH3jhvATLz7AE0kMn0FJL3WVq2lu1kuheTkdWuQUyHbd44yNXRXlQe7TX7AWPx7u4Gb1mNixSbNIAlFc1ti81khZ2rPi335Xj16wZ2PXsU3VGwZQH2+CQqqMNokcVr7A+NVoWz5KcooVnJHdUzazwDSU5zCMgRxsGFYQ9+akA43IK9GzeojW9OyEouSpsG4xVxhO211h/Rb0tw1DE9NdjXztqAijK3dCNsS+n7waOHM8Yx0b8ZdsmGcCYoTXGJzxMijkP6sDh0k1VK5ISAGsm9hiJDeyi4MIKLo4JmKrA4Ly+hi14KujgWaAWuMembhatZTXW7hjtld28CwthGKU4BIm76xDIMMoZ9FVC07w7RdpmGdBmlKOsLRkO1TjNMVanFt4r7IJ9ivlav4tgAhoPNdGBHG8NSNSIx1zJG55N+sUwbs4p6vbW9c2oPRvPWEfOjYev3oGaJeajGtC9JzVdQl2UaiNef3CzZL61Tba0a3IQ9xdG3gPeisvf4E00d43HtZmGmnqe1g1f2pHw1SFans3gEyfD3wcqnnA6Q9AMGaH6mnqj4OO3s+p2xN/WGk45YnHuzTl+9/hr/OlC0x2/6LLtX

# ポイント
## テーブル全体の横幅はstyleで指定しないといけない

`v-data-table-server`のpropsには、widthというpropsがあったのですが、指定しても機能せずでした。
したがって、styleを使って指定が必要です。
```vue
<v-data-table-server
  :style="width: 600px"
```

変数を使う場合は以下のように書きます。

```vue
<template>
  <v-data-table-server
    :style="{ width: tableWidth }"
  />
</template>
<script setup>
  import { ref, watch } from 'vue'

  const tableWidth = ref('');
</script>
```


## ヘッダ全てに横幅を指定すると無視される
最初に、**テーブル全体の横幅はstyleで指定しないといけない**という話をしたのは、このポイントを回避するためで、
**テーブル全体の横幅を設定せず、ヘッダ全てに横幅を設定**すると、設定したヘッダの横幅が無視されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/966e9712-df30-4398-b07f-fe81df5e376c.png)

```js
// 長くなるので省略してます
const headers = ref([
    {
      title: 'Dessert (100g serving)',
      align: 'start',
      sortable: false,
      key: 'name',
      width: '100px',
    },
    {
      title: 'Calories',
      key: 'calories',
      align: 'end',
      width: '100px',
    },
    ...
  ])
```

下記のように、一つでも横幅を設定しないヘッダがあると、他のヘッダは設定した横幅に従います。


```js
// 長くなるので省略してます
const headers = ref([
    {
      title: 'Dessert (100g serving)',
      align: 'start',
      sortable: false,
      key: 'name',
      width: '100px',
    },
    {
      title: 'Calories',
      key: 'calories',
      align: 'end',
      width: '100px',
    },
    ...
    // Ironは横幅を指定しない
    {
      title: 'Iron (%)',
      key: 'iron',
      align: 'end',
    },
  ])
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/1b6a0a42-e9c8-40f5-af45-8557ef093b46.png)


### 回避方法
この章の冒頭でも書きましたが、回避するにはテーブルの横幅を設定してあげると回避できます

v-data-table-serverに下記を追加する

```diff_vue
<v-data-table-server
+  :style="width: 600px"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/01127ffc-877b-43cf-bb2e-7eacb2ce1bb8.png)


# 小ネタ
JSやVueに不慣れなので、詰まったポイントを備忘録として記載します

### styleの指定方法

styleを渡すときに変数を使いたい場合は下記のようにしないといけない

`:style="{ width: tableWidth }"`

### Booleanを渡す方法

BooleanをPropsで渡す場合は、:をつける必要がある
`:isFlag="false"`

:::note info 
ChatGPTの回答

false を渡す場合は、必ず v-bind (省略形 :) を使う必要があります。
単に isFlag="false" と書くと、文字列の "false" が渡されてしまい、JavaScript では文字列 "false" は truthy (真と評価される値) とみなされるため、意図通りに動作しません
:::

### styleタグ内でJSを使う
```vue
<script setup>
const props = defineProps({
  isFlag: {
    type: Boolean,
    required: false,
    default: true,
  },
})
</script>
<template>
</template>
<style>
// ここでJSを使いたい場合はv-bindを使う
body {
  width: v-bind('props.isFlag ? "100px" : "200px"');
}
</style>
```

### 文字列 → 数値の変換
JSでは文字列をいい感じに変換してくれる
```
const width = "100px";
const num = parseInt(width, 10)
console.log(num); // 100
```