1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

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

前提

  • 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>

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?