1
Help us understand the problem. What are the problem?

posted at

updated at

Vue2 コンポーネントまとめ ②

はじめに

Vue.jsを理解する上で重要なコンポーネント。
その理解を深めるためにまとめておきます。

データの受け渡し

次はコンポーネント間でのデータの受け渡しについてまとめます。
コンポーネント間でのデータの受け渡しができれば別々に作成されたコンポーネントを連携して利用することができます。

そもそもコンポーネントの親子関係とは

コンポーネントのテンプレートで他のコンポーネントを使うことを、コンポーネントの親子関係と呼びます。
親コンポーネントとはこの例では、hello-worldのコンポーネントを利用したVueインスタンスです。

html
<div id="app">
    <hello-world></hello-world>
</div>

子コンポーネントはVue.componentで作成したhello-worldになります。

javascript
Vue.component('hello-world',{
  template : '<h1>Hello World</h1>'
})

Vueにおけるコンポーネントの親子関係は

  • 親はコンポーネントを利用する側
  • 子はコンポーネントを利用される側

になります。

上記の例だとのHTMLが親、Vueコンポーネントが子になるとのこと。
ややこしいですが。

親子関係はVueインスタンスとコンポーネントのパターンだけでなく
コンポーネントとコンポーネントというパターンもあります。

javascript
Vue.component('comp-parent', {
  template: '<div><h1>componentの親</h1><comp-child /></div>'
})

Vue.component('comp-child', {
  template: '<p>componentの子</p>'
})

new Vue({
  el: '#app'
})

See the Pen Vue.js vueコンポーネント練習10 by morioka (@rm5912) on CodePen.

親から子へのデータの受け渡し

親コンポーネントから子コンポーネントへのデータの受け渡しにはpropsを使います。

javascript
Vue.component('hello-world',{
  template: '<h1>Hello World and {{ message }}</h1>',
  props: ['message']
html
<div id="app">
  <hello-world message="Hello Vue.js"></hello-world>
  <hello-world message="Hello Japan"></hello-world>
</div>

この場合親コンポーネントはmessage属性としてその値を渡します。
messageの値が親コンポーネントから子コンポーネントに渡されて表示されています。

See the Pen Vue.js vueコンポーネント練習9 by morioka (@rm5912) on CodePen.

propsとは

そうなんだ〜とは思っていただけたかと思いますが、いまいちそのpropsってなに?って方も多いと思います。
propsを利用することで親コンポーネントから子コンポーネントに値を渡すことができます。
値を渡すというと関数がありますが、関数に値を渡す時に引数を利用するのと同様にpropsでも引数のようにコンポーネントに対して値を渡すことができます。
コンポーネントへpropsを渡すことでコンポーネント内で決められた処理を行うことができます。

親のdataを子へ

messageに直接、値を入れていましたが、
v-bindを使うと親コンポーネントのdataを子コンポーネントに渡すことができます。
inputTextを親コンポーネントのdataに追加します。

javascript
Vue.component('hello-world',{
  template: '<h1>Hello World and {{ message }}</h1>',
  props: ['message']
})  

var app = new Vue({
  el: '#app',
  data: {
    inputText: ''
  }
})  
html
<div id="app">
  <input type="text" v-model="inputText">
  <hello-world v-bind:message="inputText"></hello-world>
</div>

v-modelディレクティブを使って双方向データバインディングしています。
入力すると即座に出力されているのがわかるかと思います。

See the Pen Vue.js vueコンポーネント練習11 by morioka (@rm5912) on CodePen.

v-forでリストデータを子に渡す

v-forを使うことで配列を子コンポーネントに渡すことができます。

javascript
Vue.component('flamework',{
  template: '<div><h2>{{ flame.title }}</h2><p>{{ flame.content }}</p></div>',
  props: ['flame']
})  

new Vue({
  el: '#app',
  data: {
    flames: [
      {'id':0, 'title': 'vue.js', 'content': 'JavaScriptフレームワーク'},
      {'id':1, 'title': 'Rails', 'content': 'Rubyフレームワーク'},
      {'id':2, 'title': 'Laravel', 'content': 'PHPフレームワーク'},
    ]
  }
})

子コンポーネントはflameをオブジェクトとして受け取りtemplate内でflameの展開を行なっています。

html
<div id="app">
  <flamework v-for="flame in flames" v-bind:key="flame.id" v-bind:flame="flame"></b>
</div>

v-bind:keyを設定しないとエラーになりますので設定しましょう。

See the Pen Vue.js vueコンポーネント練習12 by morioka (@rm5912) on CodePen.

またオブジェクトではなく、変数としても渡すことができます。

See the Pen Vue.js vueコンポーネント練習13 by morioka (@rm5912) on CodePen.

子から親へイベントを送る

親から子へはv-bindとpropsを使います。
子から親へのデータの受け渡しは$emitというメソッドを使います。

まずは$emitを理解するためにイベントを渡してみます。

アラートが発生するイベントを作成します。

javascript
Vue.component('emit-event, {
  template: '<button v-on:click="clickEvent">ボタン</button>

クリックイベントが発火したら、子コンポーネントはそのイベントの処理で$emitを実行して親に渡したいイベントを発火させます。

javascript
methods: {
    clickEvent: function(){
      this.$emit('from-child')
    }
  } 

親は子から来るイベントに対するメソッドを設定して子から来るイベントを待ちます。

html
<div id="app">
  <emit-event v-on:from-child="alertMessage"></emit-event>
</div>
javascript
var app = new Vue({
  el: '#app',
  methods:{
    alertMessage: function(){
      alert('子からイベント受け取ったよ')
    }
  }
})  

親は子が発生したイベントを受け取って親が用意していたメソッドを実行します。
ややこしいですね。

See the Pen Vue.js vueコンポーネント練習14 by morioka (@rm5912) on CodePen.

また子コンポーネントでそのまま$emitをtemplateに書くこともできるようです。
その場合はmethodsを書く必要がなくなります。

javascript
template: `<button v-on:click="$emit('from-child')">ボタン</button>`,

子から親へデータを渡す

次は子コンポーネント側のdataを親側に送る処理をしてみます。

子コンポーネントに入力フォームを作成して入力後に送信ボタンを押すとイベントが発火して
$emitメソッドを使って入力した内容を親コンポーネントに送ります。

javascript
Vue.component('emit-event',{
  template: `<div>
  <input type="text" v-model="inputText">
  <button v-on:click="clickEvent">送信ボタン</button>
  </div>`,
  data: function(){
    return {
      inputText : ''
    }
  },
  methods: {
    clickEvent: function(){
      this.$emit('from-child',this.inputText)
    }
  },
})  

$emitは引数を取ることができます。
引数を利用してデータを送ります。また複数のデータを渡す場合はオブジェクトを利用して渡すことができます。

html
<div id="app">
  <p>{{ message }}</p>
  <emit-event v-on:from-child="receiveMessage"></emit-event>
</div>

入力されて受け取ったデータをdataのmessageに設定します。

javascript
var app = new Vue({
  el: '#app',
  data: {
    message: ''
  },
  methods:{
    receiveMessage: function(message){
      this.message = message;
    }
  }
})

See the Pen Vue.js vueコンポーネント練習15 by morioka (@rm5912) on CodePen.

子コンポーネントのフォームに入力されたテキストが親コンポーネントに渡されて、表示されています。

終わりに

コンポーネントについてまとめてみました。
まとめたもののまだまだ理解が足りないなと感じています。。。
slotについてはまた次にまとめてみたいと思います。

参考サイト
REFFECT vue.jsコンポーネントの基礎
Qiita [Vue.js]コンポーネントの親子関係とpropsについて
Qiita propsと$emitでデータを引き渡す

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?