Vue.jsの親子コンポーネント間の通信は、原則としてpropsと$emitを使用します。
子コンポーネントはpropsで親コンポーネントからデータを受け取り、$emitでイベントを発行することで親コンポーネントに通知を行います。
$emitでは引数にデータを指定することで親コンポーネントにデータを渡すこともできます。
Vue.jsでは上記の「Props down, Event up」が基本になりますが、別の方法で親子コンポーネント間でデータを参照する方法も用意されていませす。
そこで今回は、親コンポーネントを参照する$parent、子コンポーネントなどのHTML要素を参照する$refs、コンポーネントツリーのルートを参照する$rootの3つのインスタンスプロパティを紹介します。
目次
$parentプロパティ
$parentプロパティは、現在のコンポーネントの親にあたるコンポーネントのインスタンスを返します。
$parentプロパティの書式
$parentプロパティは、子コンポーネント側で以下のように使用します。
1 |
this.$parent.親要素のプロパティ |
親要素のプロパティには、dataオプションに定義したプロパティや、computedオプションに定義したプロパティを指定できます。
$parentプロパティの使用例
以下に$parentプロパティを使用して親コンポーネントのデータを参照する例を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- 子コンポーネント --> <script type="text/x-template" id="custom-component"> <div> <button v-on:click="onClick">ボタン</button> </div> <div> <textarea v-bind:value="message" rows="2" cols="30"></textarea> </div> </script> <!-- 親アプリケーション --> <div id="app"> <custom-component></custom-component> </div> |
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 |
// 子コンポーネント const customComponent = { template: '#custom-component', data: function() { return { message: '' } }, methods: { onClick: function() { const valueOfData = this.$parent.valueOfData; const valueOfComputed = this.$parent.valueOfComputed; this.message = `${valueOfData} ${valueOfComputed}`; } } } // 親アプリケーション Vue.createApp({ components: { 'custom-component': customComponent }, data: function() { return { valueOfData: 'dataオプションのデータ' } }, computed: { valueOfComputed: function() { return 'computedオプションのデータ'; } } }).mount('#app') |
ここでは、親のアプリケーションに定義したdataオプションとcomputedオプションのプロパティを、子コンポーネントから参照してテキストボックスに表示しています。
上記の例のコードを実行すると以下の画面が表示されます。
$refsプロパティ
$refsプロパティは、コンポーネント(カスタム要素)のインスタンスを返します。
$refsプロパティの書式
$parentプロパティは、親コンポーネント側で以下のように使用します。
1 |
this.$refs.HTMLに定義したref属性の名前 |
$refsプロパティを使うためにはHTMLテンプレートに配置する要素にref属性を指定します。ref属性の引数には、$refsプロパティを使用して参照する名前を指定します。
1 |
<要素名 ref="名前"> |
$refsプロパティの使用例
以下に$refsプロパティを使用して親コンポーネントのデータを参照する例を示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- 子コンポーネント --> <script type="text/x-template" id="custom-component"> <div>data: {{messageOfChild}}</div> </script> <!-- 親アプリケーション --> <div id="app"> <custom-component ref="child"></custom-component> <div> <button v-on:click="onClick">ボタン</button> </div> <div>子コンポーネントのdata: {{message}}</div> </div> |
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 |
// 子コンポーネント const customComponent = { template: '#custom-component', data: function() { return { messageOfChild: 'ABC' } } } // 親アプリケーション Vue.createApp({ components: { 'custom-component': customComponent }, data: function() { return { message: '' } }, methods: { onClick: function() { this.message = this.$refs.child.messageOfChild; } } }).mount('#app') |
ここでは、子コンポーネントに定義したdataオプションのmessageOfChildプロパティの値を親のアプリケーションから参照してます。
HTMLテンプレートで子コンポーネントのカスタム要素の「custom-component」を配置してref属性に「child」という名前を付けています。
上記の例のコードを実行すると以下の画面が表示されます。
上記の例では、コンポーネント要素に対してref属性を指定して$refsプロパティで参照していますが、$refsプロパティを使用した要素の取得はHTMLに標準で用意されている要素でも使用できます。
例えばinput要素を取得する場合は次のようになります。
1 2 3 4 |
<div id="app"> <input ref="textBox" v-on:input="onInput" /> </div> |
1 2 3 4 5 6 7 |
Vue.createApp({ methods: { onInput: function() { console.log(this.$refs.textBox.value); } } }).mount('#app') |
ここでは、input要素のinputイベントをv-onディレクティブでonInputメソッドにバインドし、onInputメソッドでは$refsプロパティを利用してinput要素を参照して、input要素のvalueをコンソールログに出力しています。
$rootプロパティ
$rootプロパティは、コンポーネント階層のルート(トップ階層)のインスタンスを返します。
コンポーネントの階層が2階層の場合は$parentプロパティと同じインスタンスになります。
$rootプロパティの書式
$rootプロパティは、子コンポーネント側で以下のように使用します。
1 |
this.$root.ルート要素のプロパティ |
ルート要素のプロパティには$parentプロパティと同様に、dataオプションに定義したプロパティや、computedオプションに定義したプロパティを指定できます。
$rootプロパティの使用例
以下に$rootプロパティを使用してルートコンポーネントのデータを参照する例を示します。
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 |
<!-- 子コンポーネント --> <script type="text/x-template" id="custom-child"> <button v-on:click="onClick">子コンポーネント</button> <div>data: {{message}}</div> <div>$rootで参照: {{messageOfRoot}}</div> <div>$parentで参照: {{messageOfParent}}</div> <hr> </script> <!-- 親コンポーネント --> <script type="text/x-template" id="custom-parent"> <custom-child></custom-child> <button v-on:click="onClick">親コンポーネント</button> <div>data: {{message}}</div> <div>$rootで参照: {{messageOfRoot}}</div> <div>$parentで参照: {{messageOfParent}}</div> <hr> </script> <!-- ルートアプリケーション --> <div id="app"> <custom-parent></custom-parent> <div> {{messageOfParent}} </div> </div> |
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 |
// 子コンポーネント const customChild = { template: '#custom-child', data: function() { return { message: '孫コンポーネント', messageOfRoot: '', messageOfParent: '' } }, methods: { onClick: function() { this.messageOfRoot = this.$root.message; this.messageOfParent = this.$parent.message; } } } // 親コンポーネント const customParent = { components: { 'custom-child': customChild }, template: '#custom-parent', data: function() { return { message: '親コンポーネント', messageOfRoot: '', messageOfParent: '' } }, methods: { onClick: function() { this.messageOfRoot = this.$root.message; this.messageOfParent = this.$parent.message; } } } // ルートアプリケーション Vue.createApp({ components: { 'custom-parent': customParent }, data: function() { return { message: 'ルートアプリケーション' } } }).mount('#app') |
ここでは、子コンポーネントと親コンポーネントとルートアプリケーションの3階層でコンポーネントを配置しています。
子コンポーネントでは、$rootプロパティでルートアプリケーションのデータを参照し、$parentプロパティで親コンポーネントのデータを参照しています。
親コンポーネントでは、$rootプロパティ、$parentプロパティでルートアプリケーションのデータを参照しています。
上記の例のコードを実行すると以下の画面が表示されます。
$parent、$refs、$rootの利用について
props、$emitを利用しないデータのやり取りは一見便利ですが、コンポーネントの構造や階層が複雑になるとデータの流れが不明瞭になります。
$parent、$refs、$rootを利用したデータの交換は、props、$emitを利用したデータのやり取りができない場合や、props、$emitを利用することでパフォーマンスが悪くなる場合などに限り利用してください。
$parent、$refs、$rootによるデータの通信は、あくまでも例外的な手法になりますので、必要かどうかを検討してから利用してください。