LoginSignup
5
4

More than 3 years have passed since last update.

Checkbox の Vue コンポーネントを作成する Tips

Posted at

前提

  • vue-property-decorator
  • TypeScript

やりたいこと

ただのチェックボックスをコンポーネント化して複数のページから使いたい。

capture.gif

やり方

大きく2ステップ。

Checkbox を親コンポーネントから渡した値を設定する。

子は prop を受け取るようにして。

@Component
export default class MyCheckbox extends Vue {
  @Prop({ default: false }) checked

親はデータを渡すだけです。

<my-checkbox v-model="isChecked"></my-checkbox>

Checkbox の変更を親コンポーネントへ通知する。

emit を利用して更新された値を通知してあげます。

<input 
  id="checkbox" 
  type="checkbox" 
  :checked="checked" 
  @input="$emit('input', $event.target.checked)">

ハマったところ

チェックボックスの View が更新されない

スクリーンショット 2020-03-09 11.15.05.png

^こういう状態が起きていました。value には true が設定されているが、チェックボックスに反映されていません。

v-model は :value @input のシンタックスシュガーという理解だったので :value="checked" を設定していたのですが、チェックの状態を同期したいので正しくは :checked="checked" でした。

警告が表示される

スクリーンショット 2020-03-09 11.20.44.png

Vue には利用されるコンポーネント(子コンポーネント)は props で渡された値を変更してはいけないという原則があり警告が表示されます。

親コンポーネントへの通知は以下のように設定していました。
これでは props のデータを上書きしてしまいます。

@input="checked = $event.target.checked"

以下のように通知することで警告なしに同様の結果を得られることができました。

@input="$emit('input', $event.target.checked)"

まとめ

  • checkbox の bool 値を制御したい場合は value ではなく checked を。
  • input の変更を親に通知して値を変更したい場合は $emit('input', xxx) を利用する。

全体図

<template>
  <div>
    <my-checkbox v-model="isChecked" label="チェックボックス"></my-checkbox>
    <p>設定された値:{{ isChecked }}</p>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import MyCheckbox from '~/components/MyCheckbox.vue'
@Component({
  components: {
    MyCheckbox
  }
})
export default class index extends Vue {
  isChecked = true
}
</script>

<template>
  <div>
    <label>{{ label }}
      <input id="checkbox" type="checkbox" :checked="checked" @input="$emit('input', $event.target.checked)">
    </label>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'

@Component
export default class MyCheckbox extends Vue {
  @Prop({ default: false }) checked
  @Prop() label
}
</script>

<style scoped>
  /* 好きなスタイルを当てる */
</style>

参考

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4