子コンポーネントのデザインオプションを親コンポーネントから切り替える[Vue.js, Vuetify]


Vuetifyのデザインコンポーネントはとても便利で、オプションをちょっと書くだけでUIのデザインや機能まで簡単にカスタマイズできます。
さらに、少し工夫するだけで親コンポーネントからもオプション類を操作できるため、その手順をまとめます。

やりたいこと

こんな感じで、バレーボールのポジションを選択するv-selectだけのコンポーネントを作ります。
(なぜバレーボールなのかは無視してください)

子コンポーネント
<template>
  <v-select
    prepend-icon=" mdi-volleyball "
    :items="positionList"
    label="ポジション"
  ></v-select>
</template>

<script>
export default {
  data() {
    return {
      positionList: [
        'ウィングスパイカー',
        'ミドルブロッカー',
        'セッター',
        'リベロ',
      ],
    }
  },
}
</script>

※本来は子コンポーネントで選択された値を親に返すためにv-modelでバインドしたり$emitを用いた処理を書いたりしないといけないですが、本題から外れるため省略しています。

この入力フォームを開くと以下のように選択リストが展開され、一つのポジションを選択できます。

ここで、v-selectmultipleというオプションを与えると複数選択できるフォームになります。

子コンポーネント(抜粋)
<template>
  <v-select
    prepend-icon=" mdi-volleyball "
    :items="positionList"
    label="ポジション"
    multiple
  ></v-select>
</template>

「親Aからこのコンポーネントを呼ぶときは単一選択でよいが親Bから呼ぶときは複数選択したい」ということもあるかと思います。例えば、「私はこのポジションです」という使い方なら単一でよいですが、「経験したことがあるポジション」を選択するときは、複数選択したいでしょう。

このmultipleを、親コンポーネントから切り替えます。

propsでBoolean値を渡す

このmultipleVuetify公式を見るとBoolean型でコントロールされていることがわかります。

したがって、multipleを何らかのBoolean型の変数でバインドし、かつその変数を親から与えることで、マルチとシングルを切り替えることができそうです。

よって、親・子のコードは以下の通りになります。

親A(single)
<position-selecer> </position-selecer>
親B(multiple)
<position-selecer
 :multiple-flg="true"
>
</position-selecer>
子(position-selecer)
<template>
  <v-select
    prepend-icon=" mdi-volleyball "
    :items="positionList"
    label="ポジション"
    :multiple="multipleFlg"
  ></v-select>
</template>

<script>
export default {
  props: {
    multipleFlg: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      positionList: [
        'ウィングスパイカー',
        'ミドルブロッカー',
        'セッター',
        'リベロ',
      ],
    }
  },
}
</script>

まず、子のv-selectmultipleを任意のBoolean型の変数にバインドします。これを親から受け取りたいのでpropsに指定するのですが、普通に記述するだけだと子はすべてString型として受け取ってしまい、true/falseとして解釈できません。これは、propsをオブジェクト形式で記述し、typeBooleanと指定することで解決します。

また、今回は明示的な指定があったときだけマルチにしたいので、デフォルト値をfalseにしています。

次に親側の記述についてです。
上述のとおり子のデフォルトはmultiple: falseであるため、何もしなければシングルで表示されます。なので親Aは特に何か指定する必要はありません。

他方、親Bはマルチで呼びたいためmultiple-flgtrueを設定しています。このとき、普通は静的な値をpropsで渡す際に:multipleのようにバインドする必要はないのですが、今回のように子がオブジェクト形式で型を指定してpropsを受け取るような場合は、バインドした状態で渡す必要があります。(特にscript部で何かする必要はなく、template部で形式的にバインドするだけOKです)

以上のようにすることで、親からの呼び出しに応じて子のオプションを切り替えて使うことができました!
細かいデザイン的な要素も親から与えることで決定できるため、子コンポーネントの再利用性が高まると思います。

参考

Vueのpropsの書き方・使い方について解説