子コンポーネントから別の子にデータをリレーする方法

by bc_rikko

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.0/css/bulma.min.css">
<h1 class="title">子から別の子にデータを渡す方法</h1>
<h2 class="subtitle">子→親→子でデータをリレーする</h2>

<!--============================================
  親コンポーネントが橋渡しする方法
============================================-->
<div id="parent-a" class="container">
  <h3 class="title is-4">方法1)親コンポーネントが橋渡しする方法</h3>
  <!-- Parent -->
  <div class="field">
    <label class="label">parent</label>
    <p class="subtitle" v-text="parentText"></p>
  </div>
  
  <!-- Child1 -->
  <child-a-1 v-model="parentText"></child-a-1>
  <!-- Child2 -->
  <child-a-2 :text="parentText"></child-a-2>
</div>

<script type="text/x-template" id="child-a-1">
  <div class="field">
    <label class="label">child-a-1</label>
    <input class="input" type="text" @input="changeInput">
  </div>
</script>

<script type="text/x-template" id="child-a-2">
  <div class="field">
    <label class="label">child-a-2</label>
    <p class="subtitle" v-text="text"></p>
  </div>
</script>


<!--============================================
  子1からEventEmitで子2に渡す方法
============================================-->
<div id="parent-b" class="container">
  <h3 class="title is-4">方法2)子1からEventEmitで子2に渡す方法</h3>
  
  <!-- Child1 -->
  <child-b-1></child-b-1>
  <!-- Child2 -->
  <child-b-2></child-b-2>
</div>

<script type="text/x-template" id="child-b-1">
  <div class="field">
    <label class="label">child-b-1</label>
    <input class="input" type="text" v-model="text">
    <button class="button is-light" @click="submit">Sent Text to Child-B-2</button>
  </div>
</script>

<script type="text/x-template" id="child-b-2">
  <div class="field">
    <label class="label">child-b-2</label>
    <p class="subtitle" v-text="text"></p>
  </div>
</script>

CSS

body {
  margin: 10px;
}
.container {
  margin: 20px;
  padding: 10px;
  border: 4px dashed rgba(0,0,0,.5)
}

JavaScript

// import [email protected] [email protected]
// x-templateはデモや極小アプリ以外は非推奨

/******************************************
 * 1.親コンポーネントが橋渡しする
 * ※ this.$emitやthis.$parent.$emitの部分をグローバルVM経由で実行することも可能
 *   参考: https://jp.vuejs.org/v2/guide/components.html#親子間以外の通信
 *******************************************/
const ChildA1 = Vue.component('child-a-1', {
  template: '#child-a-1',
  methods: {
    changeInput (e) {
      // v-modelで指定したparentTextを変更するイベント
      this.$emit('input', e.target.value);
    }
  }
});

const ChildA2 = Vue.component('child-a-2', {
  template: '#child-a-2',
  props: {
    // 親からtextをもらう
    text: String
  }
});

const vm1 = new Vue({
  el: "#parent-a",
  components: {
    ChildA1,
    ChildA2
  },
  data () {
    return {
      parentText: ''
    }
  }
});


/******************************************
 * 2.子1からEventEmitで子2に渡す方法
 *******************************************/
 const vm = new Vue();
const ChildB1 = Vue.component('child-b-1', {
  template: '#child-b-1',
  data () {
    return {
      text: ''
    }
  },
  methods: {
    submit () {
      // send-textイベントを発火させる
      vm.$emit('send-text', this.text)
    }
  }
});

const ChildB2 = Vue.component('child-b-2', {
  template: '#child-b-2',
  data () {
    return {
      text: ''
    }
  },
  created () {
    // どこから来るかわからないけど`send-text`イベントを待ち受ける
    vm.$on('send-text', this.changeText)
  },
  methods: {
    changeText (text) {
      this.text = text;
    }
  }
});

const vmB = new Vue({
  el: "#parent-b",
  components: {
    ChildB1,
    ChildB2
  }
});