技術っぽいことを書いてみるブログ

PythonとかVue.jsとか技術的なことについて書いていきます。

Vue.js TIPS ~親⇔子⇔孫コンポーネントでの双方向データバインディングについて~

はじめに

Vue.jsを使ってWEBアプリを構築する際、コンポーネント化を行い、部品の再利用性を高めると思います。
その際、親コンポーネント⇔子コンポーネント⇔孫コンポーネントでの値の受け渡し(双方向データバインディング)について、
検討してみたので、備忘録を残します。

やりたい事

コンポーネントで保持しているデータを子コンポーネントに渡し、
コンポーネントでは孫コンポーネントに受け取った値を渡して、
コンポーネントではドロップダウンの初期選択を行う。
コンポーネントのドロップダウンで選択を変更した場合、子コンポーネントそして親コンポーネントへと値を戻す。
図にすると以下のような感じ。
f:id:where-is-wally:20200620100938p:plain

やってみた

▼親コンポーネント(Sample0.vue)

<template>
  <div>
    <sample1 v-model="selectedId"></sample1>
    selectedId: {{ selectedId }}
  </div>  
</template>

<script lang="ts">
import Vue from 'vue';
import Sample1 from "./Sample1.vue";

export default Vue.extend({
  name: "Sample0",
  components: {
    Sample1
  },
  data(){
    return {
      selectedId: 5
    }
  },
  methods: {
    checkData: function(){
      alert(this.selectedId);
    }  
  }
})
</script>
コンポーネントのポイント

▼子コンポーネント(Sample1.vue)

<template>
  <div>
    <label>テスト</label>
    <sample2 v-model="selectedId" @input="$emit('input', $data.selectedId);"></sample2>
  </div>  
</template>

<script lang="ts">
import Vue from 'vue';
import Sample2 from "./Sample2.vue";

export default Vue.extend({
  name: "Sample1",
  components: {
    Sample2
  },
  props: ['value'],
  data() {
    return {
      selectedId : this.value
    }
  }
})
</script>
コンポーネントのポイント
  • コンポーネントで渡された値は、propsのvalueで受け取る。
  • propsは、読み取り専用項目なので、propsのvalueで受け取った値は初期値として使い、 dataプロパティのselectedId に代入しておく
  • selectedIdは、v-modelで双方向データバインディングさせる
  • コンポーネントの値を更新するため、v-on.input(@input)で、$emitでイベントを通知する。

▼孫コンポーネント(Samle2.vue)

<template>
  <div>
    <sui-dropdown
    selection
    :options="options"
    v-model="selectedValue"
    @input="$emit('input', $data.selectedValue);"
    />
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
  name : "Sample2",
  props: ['value'],
  data(){
    return {
      selectedValue: this.value,
      options: [
        { text: 'text1', value: 1 },
        { text: 'text2', value: 2 },
        { text: 'text3', value: 3 },
        { text: 'text4', value: 4 },
        { text: 'text5', value: 5 },
        { text: 'text6', value: 6 },
        { text: 'text7', value: 7 },
        { text: 'text8', value: 8 },
        { text: 'text9', value: 9 }
      ]
    }  
  },
  methods: {
    emitInput: function(): void{
      this.$emit('input', this.selectedValue);
    }
  }
})
</script>
コンポーネントのポイント

実行してみた

f:id:where-is-wally:20200620103430p:plain
初期値の5が選択されている

f:id:where-is-wally:20200620103518p:plain
コンポーネントのドロップダウンを変更すると、親コンポネントの値も変わっている

メモ

上記の例では、valueをpropsで受けていますが、
コンポーネントの要件によっては、value以外で受け取りたいケースがあると思います。
そのときは、modelプロパティを使うことで対応するのかなと思います。 ↓参考
jp.vuejs.org

最後に・・・

もっと簡潔に書ける方法があれば、コメントください!