Vue.jsでpropsとスタイルを動的に紐付けるやり方

普段`Vuetify`や`Ionic`とったコンポーネントライブラリを使うのに慣れてるから、コンポーネント間のデータのやり取りやイベントは書ける。
けど、それをどうスタイルに紐付ければいいのか分からないってことありませんか？

```html
<DemoButton color="primary" large icon outlined />
```

上記の

* color
* large
* icon
* outlined

っていう4つの`props`をどうスタイルに紐づけるか？
スタイルも意識したコンポーネントの作成をしてみましょう。

# TL;DR
`color`のようにを値の種類が複数あるものは `style` で__上書き__
`outlined` のようにtrue/falseの真偽値で表せるものは `class` を__付与__

# コンポーネントの全体コード
動作環境としてはTypeScript化したNuxt.jsですが、概念を伝えるのが目的なので環境設定等は省略します。悪しからず。

```vuejs:DemoButton.vue
<template>
  <button type="button" :class="classes" :disabled="disabled" :style="styles">
    <slot></slot>
  </button>
</template>

<script lang="ts">
import Vue from "vue";
export default Vue.extend({
  name: "DemoButton",
  props: {
    color: {
      type: String,
      required: false,
      default: "primary"
    },
    disabled: {
      type: Boolean,
      required: false,
      default: false
    },
    outlined: {
      type: Boolean,
      required: false,
      default: false
    }
  },
  computed: {
    styles () {
      //validateColorは @/assets/scss/_variable.scss で定義した色が指定されているかどうか確かめる為に作った関数
      return {
        '--color': validateColor(this.color),
      } 
    }, 
    // バインドするクラスを生成
    classes() {
      return {
        "demo-btn": true,
        "demo-btn--outlined": this.outlined
      };
    }
  }
});
</script>
<style lang="scss" scoped>
.demo-btn {
  // デフォルトの背景色
  --color: yellow;
  // CSS変数を背景色に割り当て
  background-color: var(--color);
}
.demo-btn--outlined {
  position: relative;
  display: inline-block;
  box-sizing: border-box;
  border: solid 1px;
  border-radius: 4px;
  background-color: transparent;
}
</style>
```

# 値のパターンをを複数もつprops
上記のコードで言うと `color` が該当します。
この引数は

* primary
* secondary
* green
* error

など様々な文字列を取る可能性があります。なのでこの場合は、
__引数で指定された値を後から`style`属性で上書きする__
という方法を使います。

```scss
.demo-btn {
  // デフォルトの背景色
  --color: yellow;
  // CSS変数を背景色に割り当て
  background-color: var(--color);
}
```

CSS変数でデフォルト値を設定しておき

```vuejs

<button type="button" :class="classes" :disabled="disabled" :style="styles">
styles () {
      /*validateColorは @/assets/scss/_variable.scss
                       で定義した色が指定されているかどうか確かめる為に作った関数*/
      return {
        '--color': validateColor(this.color),
      } 
    }
```
style属性に後から代入して上書きしています。


# 値が真偽値の2パターンしかないprops
こちらは簡単です。
引数が指定された場合のみそれに対応するクラスをコンポーネントに付与するだけです。

```vuejs
<button type="button" :class="classes" :disabled="disabled" :style="styles">
<script lang="ts">
props: {
    outlined: {
      type: Boolean,
      required: false,
      default: false
    }
classes() {
      return {
        "demo-btn": true,
        "demo-btn--outlined": this.outlined
      };
    }
</script>
<style lang="scss" scoped>
.demo-btn {
  // ...
}
.demo-btn--outlined {
  // ....
}
</style>
```

# 最後に
コンポーネントライブラリを作ってみよう！ってなっても、スタイルどうすればいいの？って人に少しでも参考になれば幸いです。

参考ページのリンクを貼っておきます

* [Vue.jsでコンポーネント作るときにCSS変数つかったら色々できる](https://qiita.com/shinobu_shiva/items/31aec81a52475483791b)
* [Vuetifyのbuttonコンポーネントのtsコード](https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VBtn/VBtn.ts)
* [Vuetifyのbuttonコンポーネントのsassコード](https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/components/VBtn/VBtn.sass)