【Vue.js】vm.$emit とそれを用いた子コンポーネントから親コンポーネントへのデータ渡し

vm.$emit は引数で指定したイベントを発火させる。
これを使って、親コンポーネント内で v-on ディレクティブを使って登録したカスタムイベントを発火させることで、子から親へのデータ渡しが実現できる。

例えば、親コンポーネントである App.vue を以下のように記述する。

<template>
  <div id="app">
    <!-- カスタムイベントfavを登録。favが発火したらaddToFavoriteを実行 -->
    <Posts @fav="addToFavorite"/>
  </div>
</template>

<script>
import Posts from './components/Posts.vue'

export default {
  name: 'app',
  components: {
    Posts
  },
  data: function () {
    return {
      'favorites': []
    }
  },
  methods: {
    // コールバックとして指定されているメソッド
    // postTitleには子コンポーネントから渡されるデータが入ってくる
    addToFavorite: function(postTitle) {
      this.favorites.push(postTitle);
      console.log(this.favorites);
    }
  }
}
</script>

methods オブジェクトには addToFavorite メソッドを定義しておき、<Posts @fav="addToFavorite"/> でカスタムイベント fav を登録し、 fav が発火したら addToFavorite メソッドを実行するように記述。

そして、子コンポーネントである Posts.vue は以下のようにする。

<template>
  <div class="posts">
    <ul>
      <!-- li要素クリックでPostsコンポーネントのaddToFavメソッドが発火する -->
      <li v-for="(post, index) in posts" :key="index" @click="addToFav">
        {{ post.title }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'Posts',
  data: function () {
    return {
      'posts': [
        {'title': 'タイトル1'},
        {'title': 'タイトル2'},
        {'title': 'タイトル3'},
      ]
    }
  },
  methods: {
    addToFav: function (e) {
      // vm.$emitでカスタムイベントfavを発火させる
      // 第二引数のデータはfavで指定しているコールバックに渡される
      this.$emit('fav', e.path[0].innerText);
    }
  }
}
</script>

this.$emit('fav', e.path[0].innerText); の部分で親コンポーネントで登録したカスタムイベント fav を発火させる。
ちなみに e.path[0].innerText はクリックした要素のテキストを取得していて、これをコールバックとして指定している親コンポーネントのメソッド addToFavorite に渡している。

これで、子コンポーネントから親コンポーネントへデータを渡すことができる。