Vue.js を触って早数週間経過します。
最も理解に時間がかかった コンポーネントの連携 についてまとめてみます。

理解が怪しいところはマサカリをお願いいたします。

ゴール

子コンポーネントから親コンポーネントの関数を呼び出す

環境

  • Node.js 7.7.1
  • npm 4.4.2
  • Vue.js 2.2.4

propsでデータを渡す

props とは「 親コンポーネントからデータを受け取るためにエクスポートされた属性のリスト/ハッシュ 」です。

Vue.js > API > props
https://jp.vuejs.org/v2/api/#props

最もシンプルな例を見てみましょう。

呼び出し元

1<template>
2  <child-component foo="bar" />
3</template>

具体的には、次の定義です。
これは今まで慣れ親しんできたHTMLと同じ形式ですね。

1<[コンポーネント名] [属性]="[値]">

子コンポーネント

1<script>
2export default {
3  props: [
4    'foo'
5  ]
6}
7</script>
8

子コンポーネントに props を定義しておけば、コンポーネント呼び出し時に与えられた属性、値にアクセスすることができます。

1<template>
2  <p>{{ foo }}</p><!-- bar -->
3</template>

HTML では受け取った値をこのように出力することができます。

props + v-bindでデータを渡す

上記はリテラルを子コンポーネントに渡す方法でした。
次に v-bind を利用して親コンポーネントのデータを子コンポーネントに渡してみましょう。

Vue.js > API > v-bind
https://jp.vuejs.org/v2/api/#v-bind

呼び出し元

 1<script>
 2export default {
 3  data() {
 4    return {
 5      var: "hoge"
 6    }
 7  }
 8}
 9</script>
10
1<template>
2  <child-component v-bind:foo="var" />
3</template>

変数を定義し、子コンポーネントに与えます。

初めの例と異なるのは属性名 foo の前に v-bind が付いているかどうかだけですね。

子コンポーネント

1<script>
2export default {
3  props: [
4    'foo'
5  ]
6}
7</script>
8
1<template>
2  <p>{{ foo }}</p> <!-- hoge -->
3</template>

子コンポーネントは初めのサンプルと全く同一です。

しかしながら props 経由で受け取った foo の中身ははリテラルではななく、親で定義されたオブジェクトのため、foo の値として hoge が出力されます。

つまり、どういうことだってばよ

Vue.js では v- から始まる属性を ディレクティブ (Directive) と呼び、特別な属性 として扱います。

ディレクティブとは、 DOM 要素に対して何かを実行することをライブラリに伝達する、マークアップ中の特別なトークンです。
http://012-jp.vuejs.org/guide/directives.html

次は Vue.js にプレーンな HTML として解釈されます。

1<child-component foo="bar" />

次は v- で始まるディレクティブですね。

1<child-component v-bind:foo="var" />

v-bind は「どの属性にどの式を与えるか (束縛するか) を指示するもの」で、噛み砕くとここでは「属性 foo に式 var を適用する」という指示を行なっています。
噛み砕くと、次の形です。

1<[コンポーネント名] v-bind:[bindする属性]="[bindする式]">

bind された式は リアクティブ で、つまり元のデータである var の値を書き換えると、属性値にも即反映される実装が可能です。


ちなみに v-bind は次のように省略して記述することができます。

1<child-component :foo="var" />

プレーンな HTML と並べてみると、、、コロン (:) があるかどうか だけですね。
何この綺麗すぎる実装!!

1<child-component  foo="bar" />
2<child-component :foo="var" />

子コンポーネントから親のメソッドを呼び出す

さて、ようやくゴールとなる課題に取り掛かりましょう。

親コンポーネントのメソッドを、子コンポーネントから引数付きで呼び出します。

ちょっと無理やり感がありますが、次のようなサンプルを用意しました。
親となるコンポーネントから子にパラメーターを渡し、子は受け取ったパラメーターによって処理を分けるというイメージです。

親コンポーネント

 1<script>
 2export default {
 3  methods: {
 4    parentFunc(foo, bar) {
 5      console.log(foo)
 6      console.log(bar)
 7    }
 8  }
 9}
10</script>
11
1<template>
2  <div>
3    ボタンA<child-component v-on:call-parent="parentFunc" foo="1" bar="A" />
4    ボタンB<child-component v-on:call-parent="parentFunc" foo="2" bar="B" />
5  </div>
6</template>

親コンポーネントからは子へは、次の形で v-on を用いて イベント名 を知らせます。

1v-on:[イベント名]="[親コンポーネントメソッド]"

子コンポーネント

 1<script>
 2export default {
 3  props: [
 4    'foo',
 5    'bar'
 6  ],
 7  methods: {
 8    childFunc(foo, bar) {
 9      this.$emit('call-parent', foo, bar)
10    },
11  },
12}
13</script>
14
1<template>
2  <button v-on:click="childFunc(foo, bar)" type="button">Button</button>
3</template>

親から子へ渡ってきたのはメソッドではなく、イベント名でしたね。 子コンポーネントから親のメソッドを実行するためには、子から $emit でイベントを発火させるのがポイントです。

template から直接イベントを発生させることはできませんため、クリックイベントを一旦 子コンポーネントのメソッド ( ここでは childFunc ) で受け取り、そのメソッド内でイベントを処理します。

ボタンをクリックすると、引数に応じて console.log の値がしっかり出し分けられていることを確認できますよ。 わかるのですが、回りくどい実装ではありますよねー。

親子の連携は特殊なルールで成り立っているようで、ぜひ Vue.js の次をガイドもご覧ください。

Vue.js > ガイド > カスタムイベントとの-v-on-の使用
https://jp.vuejs.org/v2/guide/components.html#カスタムイベントとの-v-on-の使用

Vuex

過去に次のコメントをいただきました。

違うコンポーネント間でデータのやり取りしたくなったらさっさとVuex使ったほうがいい。
propsで親→子ならいいけど子から親を見るようになったら近いうちに死ぬ。

jQuery で死にたくないので Vue.js を使い始めましたが、Vue.js を使ってもでも死んでしまうなんて元も子もありません!

コンポーネントで親から子に渡すパラメーターが増えるたびに「こんなはずじゃなかった感」が募ってきておりましたので、ご指摘の通り Vuex の導入時期だと言うことを悟りました。
コメントをくださった方ありがとうございました。

おわりに

Vue.js は学習コストが低く、使いやすいライブラリです。

現在 1 プロジェクトを Vue.js で開発中ですが、要件をこなしていくとつまづきポイントや弱点がわかってきますねー。
引き続き勉強したことを記事にできればと思っています。

是非みなさんもモダンな JavaScript ライブラリで楽しい開発ライフを過ごしてください。

Vue.js入門 基礎から実践アプリケーション開発まで

川口 和也,喜多 啓介,野田 陽平,手島 拓也,片山 真也
出版社:技術評論社  発売日:2018-09-22

Amazonで詳細を見る

基礎から学ぶ Vue.js

mio
出版社:シーアンドアール研究所  発売日:2018-05-29

Amazonで詳細を見る

Vue.js: Up and Running: Building Accessible and Performant Web Apps

Callum Macrae
出版社:O'Reilly Media  発売日:2018-03-23

Amazonで詳細を見る