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
51
|
<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">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<script>
var component1 = {
template: "#child1",
data: function() {
return {
myValue: ""
}
},
methods: {
updated: function() {
this.$emit('on-child-updated', this.myValue);
}
}
}
var v = new Vue({
el: "#app",
data: function() {
return {
parentValue: ""
}
},
components: {
'child1': component1
},
methods: {
childUpdated: function(v) {
this.parentValue = v;
}
}
});
</script>
</body>
</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
63
|
<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>
<child2 v-bind:my-value="parentValue"></child2>
</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">
</script>
<script type="text/x-template" id="child2">
<div></div>
<p></p>this is child2<p></p>
c: "text" v-model="myValue">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<script>
var component1 = {
template: "#child1",
data: function() {
return {
myValue: ""
}
},
methods: {
updated: function() {
this.$emit('on-child-updated', this.myValue);
}
}
}
var component2 = {
template: "#child2",
props: ["myValue"]
}
var v = new Vue({
el: "#app",
data: function() {
return {
parentValue: ""
}
},
components: {
'child1': component1,
'child2': component2
},
methods: {
childUpdated: function(v) {
this.parentValue = v;
}
}
});
</script>
</body>
</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
49
|
<html>
<head><title>test</title></head>
<body>
<div id="app">
<p>this is parent</p>
a: <input type="text" v-model="parentValue">
<hr>
<child1 v-bind:my-value="parentValue"></child1>
<child2 v-bind:my-value="parentValue"></child2>
</div>
<script type="text/x-template" id="child1">
<div></div>
<p></p>this is child1 -> {{myValue}}<p></p>
b: "text" v-model="myValue">
</script>
<script type="text/x-template" id="child2">
<div></div>
<p></p>this is child2 -> {{myValue}}<p></p>
c: "text" v-model="myValue">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.min.js"></script>
<script>
var component1 = {
template: "#child1",
props: ["myValue"]
}
var component2 = {
template: "#child2",
props: ["myValue"]
}
var v = new Vue({
el: "#app",
data: function() {
return {
parentValue: ""
}
},
components: {
'child1': component1,
'child2': component2
}
});
</script>
</body>
</html>
|
図のように、子コンポーネントの変更は親コンポーネントに連携されませんでした。
(「a]」に"aaa"を入力した後、「b:」に"CCC"を追加入力した図)
参考URL