
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プロパティを使用して親コンポーネントのデータを参照する例を示します。
HTML
| 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> | 
JavaScript
| 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プロパティを使用して親コンポーネントのデータを参照する例を示します。
HTML
| 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> | 
JavaScript
| 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要素を取得する場合は次のようになります。
HTML
| 1 2 3 4 | <div id="app">   <input ref="textBox"          v-on:input="onInput" /> </div> | 
JavaScript
| 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プロパティを使用してルートコンポーネントのデータを参照する例を示します。
HTML
| 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> | 
JavaScript
| 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によるデータの通信は、あくまでも例外的な手法になりますので、必要かどうかを検討してから利用してください。
