Vue.jsでコンポーネント間でデータを連携する方法について、理解するのに若干時間がかかったのでまとめておきます。

連携は、公式サイトで「props down, events up」と呼ばれている方式を使います。

(https://jp.vuejs.org/v2/guide/components.html より引用)


親コンポーネント・子コンポーネント1・子コンポーネント2があるとき、子コンポーネント1と子コンポーネント2の間の連携は以下のようになります。

  • 子コンポーネント1でデータ更新時、親コンポーネントのイベントを発火する ($emit(eventName)による発火)
  • 親コンポーネントのイベントから、子コンポーネント2のデータを更新する (propsを使ったデータ連携)

これらの流れをサンプルを買いて試しながら確認します。

子コンポーネント1でデータ更新時、親コンポーネントのイベントを発火する ($emit(eventName)による発火)

子コンポーネント1のデータ更新を親コンポーネントで受け取るために、以下の設計でサンプルを作成します。

  • 親コンポーネントは、子コンポーネント1に発生する on-child-updated イベントを待ち受ける
    • イベントを受け取ると、 childUpdated メソッドを実行し、プロパティ parentValue を書き換える
  • 子コンポーネント1はプロパティ myValue が更新されたとき、 updated メソッドを実行する
    • updated メソッドの中で、 $emit(eventName) を使ってon-child-updated イベントを発生させる
      • このとき、プロパティ myValue を引数に渡す

サンプルコード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<html>
  <head><title>test</title></head>
  <body>
    <div id="app">
      <p>this is parent</p>
      a: {{parentValue}}
      <hr>
      <child1 v-on:on-child-updated="childUpdated"></child1>
    </div>
    <script type="text/x-template" id="child1">
      <div></div>
        <p></p>this is child1<p></p>
        b: "text" v-model="myValue" v-on:input="updated">
      
    &lt;/script>

    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js">&lt;/script>
    &lt;script>
    var component1 = {
      template: "#child1",
      data: function() {
        return {
          myValue: ""
        }
      },
      methods: {
        updated: function() {
          this.$emit(&#39;on-child-updated&#39;, this.myValue);
        }
      }
    }
    var v = new Vue({
      el: "#app",
      data: function() {
        return {
          parentValue: ""
        }
      },
      components: {
        &#39;child1&#39;: component1
      },
      methods: {
        childUpdated: function(v) {
          this.parentValue = v;
        }
      }
    });
    &lt;/script>
  &lt;/body>
&lt;/html>

実行し、子コンポーネント1の入力欄(「b:」)に “test” と入力したのが以下の図です。

親コンポーネントの {{parentValue}} の箇所が “test” に書き換わっているのがわかります。

親コンポーネントのイベントから、子コンポーネント2のデータを更新する (propsを使ったデータ連携)

次に、子コンポーネント2を作成し、親コンポーネントの値を子コンポーネント2へ渡すようにします。 親コンポーネントから子コンポーネントへのデータ連携には props を使い、プロパティとして連携します。

親コンポーネントの値を子コンポーネント2に渡すため、以下の設計を追加します。

  • 親コンポーネントは、プロパティ parentValue を子コンポーネント2のプロパティ myValue (DOMで指定するときは my-value ) に連携する

サンプルコード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
&lt;html>
  &lt;head>&lt;title>test&lt;/title>&lt;/head>
  &lt;body>
    &lt;div id="app">
      &lt;p>this is parent&lt;/p>
      a: {{parentValue}}
      &lt;hr>
      &lt;child1 v-on:on-child-updated="childUpdated">&lt;/child1>
      &lt;child2 v-bind:my-value="parentValue">&lt;/child2>
    &lt;/div>
    &lt;script type="text/x-template" id="child1">
      <div></div>
        <p></p>this is child1<p></p>
        b: "text" v-model="myValue" v-on:input="updated">
      
    &lt;/script>
    &lt;script type="text/x-template" id="child2">
      <div></div>
        <p></p>this is child2<p></p>
        c: "text" v-model="myValue">
      
    &lt;/script>

    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js">&lt;/script>
    &lt;script>
    var component1 = {
      template: "#child1",
      data: function() {
        return {
          myValue: ""
        }
      },
      methods: {
        updated: function() {
          this.$emit(&#39;on-child-updated&#39;, this.myValue);
        }
      }
    }
    var component2 = {
      template: "#child2",
      props: ["myValue"]
    }
    var v = new Vue({
      el: "#app",
      data: function() {
        return {
          parentValue: ""
        }
      },
      components: {
        &#39;child1&#39;: component1,
        &#39;child2&#39;: component2
      },
      methods: {
        childUpdated: function(v) {
          this.parentValue = v;
        }
      }
    });
    &lt;/script>
  &lt;/body>
&lt;/html>

実行し、子コンポーネント1の入力欄(「b:」)に “testaaa” と入力したのが以下の図です。

親コンポーネントの {{parentValue}} の箇所と、子コンポーネント2の入力欄(「c:」)が “testaaa” に書き換わっているのがわかります。

以上で、子コンポーネント1から子コンポーネント2へデータ連携できました。

ちなみにこれは無理

親コンポーネントのプロパティを共有する場合、子コンポーネントの更新が親コンポーネントに連携されませんでした、という例です。。

親コンポーネントに parentValue を定義し、2つの子コンポーネントにprops経由で連携してみます。

サンプルコード

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
&lt;html>
  &lt;head>&lt;title>test&lt;/title>&lt;/head>
  &lt;body>
    &lt;div id="app">
      &lt;p>this is parent&lt;/p>
      a: &lt;input type="text" v-model="parentValue">
      &lt;hr>
      &lt;child1 v-bind:my-value="parentValue">&lt;/child1>
      &lt;child2 v-bind:my-value="parentValue">&lt;/child2>
    &lt;/div>
    &lt;script type="text/x-template" id="child1">
      <div></div>
        <p></p>this is child1 -> {{myValue}}<p></p>
        b: "text" v-model="myValue">
      
    &lt;/script>
    &lt;script type="text/x-template" id="child2">
      <div></div>
        <p></p>this is child2 -> {{myValue}}<p></p>
        c: "text" v-model="myValue">
      
    &lt;/script>

    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js">&lt;/script>
    &lt;script>
    var component1 = {
      template: "#child1",
      props: ["myValue"]
    }
    var component2 = {
      template: "#child2",
      props: ["myValue"]
    }
    var v = new Vue({
      el: "#app",
      data: function() {
        return {
          parentValue: ""
        }
      },
      components: {
        &#39;child1&#39;: component1,
        &#39;child2&#39;: component2
      }
    });
    &lt;/script>
  &lt;/body>
&lt;/html>

図のように、子コンポーネントの変更は親コンポーネントに連携されませんでした。 (「a]」に”aaa”を入力した後、「b:」に”CCC”を追加入力した図)

参考URL