Vue.jsにおけるコンポーネントの基本

# Vue.jsのコンポーネントの基本

Vue.jsにおけるコンポーネントについて解説していきます。
<br>

## コンポーネントとは
コンポーネントとはWebサイトを構成する部品を分割し、部品ごとにソースコード(HTML、CSS、JavaScriptなど)にまとめ一つのモジュールにすることをいいます。
大抵のWebサイトには検索フォーム、ナビゲーション、ヘッダー、フッター、サイドバーに分かれていますが、ページ毎に共通のソースコードがあり、同じ内容を、毎回記載していくのはあまり効率が良くありません。<br>そこで、各パーツ毎にソースコードをまとめて共通化する事で、効率よく開発をすすめることができます。
Vue.jsでは、このコンポーネントという機能を使い、パーツを共通化しています。
<br>

## コンポーネントの作成方法
<br>コンポーネントを作成する為には、Vue.component()メゾットを使い、コンポーネントを登録する必要があります。
Vue.component()メゾットを使用することで、グローバルスコープにコンポーネントを登録することになり、以後どこからでもコンポーネントにアクセスすることができます。

```main.js
Vue.component('コンポーネント名',{
    template : HTMLの内容,
})
```
<br>コンポーネント名にはコンポーネントとして使用したい名前を自由に決めることがでます。
template以降は表示したい内容をHTMLを利用して記載します。
例えば、hello-world.js内のtemplateにHello-Worldと記述したとしましょう。
<br>

```main.js
Vue.component('hello-world, {
   template : '<h1>Hello-World</h1>'
}')
```
<br>templateの内容を表示させるために、親となるコンポーネントや他のコンポーネントにVue.component()メゾット内で登録したコンポーネント名を利用して、<hello-world></hello-world>と記述します。
<br>

```index.html
<div id="app">
  <hello-world><hello-world>
</div>
<script src="https://jp.vuejs.org/js/vue.js"></script>
<script src="hello-world.js"></script>
<script src="main.js"></script>

```
<br>main.jsにDOMノードを結びつける記述をします。
<br>

```main.js
var app = new Vue({
   el:'#app'
})
```

####表示結果<br><br>Hello-World
この様にして、<hello-world></hello-world>内に記載された内容をコンポーネントのtemplateオプションを使用し描写することができます。

######【注意点】<br>Vue.component()メゾットはnew Vue()メゾットより先に記述する必要があります。その為、コンポーネントを定義したファイル(ここではHello-World.js)はnew Vue()を記述したファイル(main.js)よりも先にHTMLに読み込む必要があります。



## Vue.component()の構成

Vue.component()メゾットの第二引数はオブジェクト形式で、templateオプションだけでなく、dataやmethodsなど様々なオプションを追加することができます。

```main.js
Vue.component('button-counter',{
  template: '<p>カウント:{{ count }} <button v-on:click="countUp">Up</button><button v-on:click="countDown">Down</button></p>',
  data: function(){
    return {
      count : 0
    }
  },
  methods: {
    countUp: function(){
      this.count++
    },    
    countDown: function(){
      this.count--
    },
  }
})	
```

htmlファイルにはbutton-counterタグを追加することで、カウンターを作成することができます。
<br>



Vue.component()のtemplateオプションに指定するテンプレートは、必ず全体を単一のタグで囲む必要があり、複数のタグで囲むとエラーが発生します。

```main.js
Vue.component('hello-world',{
    template: <div><p>Hello-World</p><p>I'm Masaki</p></div>
})
```
<br>
templateタグはテンプレート全体を ` で囲むと改行することができます。

```main.js
Vue.component('hello-world',{
    template: `
            <div>
              <p>Hello-World</p><p>I'm Masaki</p>
            </div>`
})
```

## ローカルスコープの登録
コンポーネントの登録にはグローバルスコープとローカルスコープの2つの方法があります。
Vue.component()メゾットを使用する場合はグローバルコンポーネントとなり、どこからでもコンポーネントを利用することができます。
一方でコンポーネントをローカルに登録することで、ある特定のコンポーネント以外は、参照することができないように制限をかけることができます。
ローカルへの登録は、親コンポーネントのcomponentオプションに子コンポーネントを定義することでローカルスコープとなります。
<br>

子コンポーネントにコンポーネントを定義します。

```main.js
var my-component = {
   template: '<p>{{message}}</p>',
   data: function(){
     return{
       message: '子コンポーネントです。'
  }
 }
};
```
<br>
親コンポーネントから、子コンポーネントのcomponentオプションに定義されているmy-componentというプロパティ名を関連づけます。
ローカルスコープで登録したコンポーネントは、親コンポーネントのテンプレート内でしか使用することができません。

```index.html
<div id="app">
  <my-component></my-component>
</div>
```


## コンポーネント間のデータの受け渡し（親コンポーネント ⇒ 子コンポーネント）

先に説明した親コンポーネントと子コンポーネントの連携は、コンポーネント間でデータを受け渡しができるようすることで、実施することができます。
親コンポーネントから子コンポーネントへデータを受け渡すためにはpropsオプションを子コンポーネントを定義します。
<br>

```main.js
Vue.component('hello-world',{
  template: '
     <h1>
         {{ message }}
     </h1>',
  props: ['message']
})	
```
<br>
次に親のテンプレートで子コンポーネントのタグ属性(ここではhello-world)を追加します。

```index.html
<div id="#app">
   <hello-world message="hello-world"></hello-world>
</div>

```
このように子コンポーネントのpropsに定義しているプロパティと同じ名前を使用し、message属性のデータが親コンポーネントから子コンポーネントに渡されることになります。
<br>
## コンポーネント間のデータの受け渡し（子コンポーネント ⇒ 親コンポーネント）

子から親へデータを渡す場合、$emitメゾットを利用して、データの受け渡しを行います。
下記例は子コンポーネント側のボタンに対して、クリックイベントを設定してます。
子の$emit()メゾットを実行して、child-clickイベントを発生させ、親のイベントハンドラが呼び出されます。


```main.js
Vue.component('my-vue', {
　 template:`
    <div>
       <button :click="click">値下げする。</button>
    </div>`,
    props: ['price'],
    methods: {
     click: function(){
        this.$emit('child-click');
  }
 }
});
```
<br>

```index.html
<div id="app">
    <my-vue :child-click="priceDown" v-bind:price="price"></my-vue>
</div>

```
<br>
最後に親にイベントハンドラ(ここではpriceDOwn)を定義して、子の値下げボタンをクリックするたびに、親のpriceが100円ずつ減少するように設定します。

```parent.js
var app = new Vue ({
     el:'#app',
     data: {
       price: 1000
  },
   methods:{
      priceDown: function(){
        this.price -=100;
    }
  }
})
```

以上です。