Vue.jsを１から学んでみた〜Vue コンポーネント〜

[Vue.js を１から学んでみた。](https://qiita.com/sh-watanabe/items/c7fc086a4ea5c707fbd3)にて書いてきましたが、
長くなり編集しにくくなってきたので、分割しました（こんなやりかたしないのかな？知りたい。）

## 7.Vueコンポーネント

### 基本

#### 前提：コンポーネントを使わない場合
Vueインスタンスを一つ作成した場合、DOMとして展開されるのは一つだけ。

```sample7-1.html
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app7-1"></div>
<!-- これは二つ目なので無視される --> 
<div id="app7-1"></div>
<p>これは表示される</p>
```
```sample7-1.js
var vm = new Vue({
  el: '#app7-1',
  data: {
    message: '1つしか表示されないはず'
  },
  // template→renderに
  render: function(createElement) {
  	return createElement('h1', this.message)
  }
})
```

*結果*
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/1273618f-03a7-5018-15ac-0db8caf4e0cf.png)

上記のように、vmインスタンスをhtmlで使い回すことができない。。

### 命名規則

ケバブケースかパスカルケースならOK。

* ケバブケース： `first-name`
* パスカルケース： `FirstName`

どっちかに統一させることが大事。

パスカルケースでおすすめ。理由は以下の通り。

* JavaScriptでケバブケースは使わないため。
* HTMLタグと見分けつきやすい。パスカルケースは、Vueコンポーネントとわかりやすい。

#### コンポーネント使用例
同じインスタンスを複数使う場合、**Vueコンポーネント**を使用する

```sample7-2.html
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

<div id="app7-2">
  <Component-name></component-name>
  <component-name></component-name>
  <component-name></component-name>
  
  <!-- これはvmインスタンスができてから宣言されるため、使えない -->
  <component-name2></component-name2>
</div>

<p>最下層</p>
<!-- 以下はマウントされていないので使えない -->
<component-name></component-name>
```
```sample7-2.js
// 第１引数：コンポーネント名
Vue.component('component-name', {
  // 第２引数：Vueコンポーネント用の書き方色々
  // 今回は簡単にtemplateだけ
  template: '<p>2つ以上表示される</p>'
});

var vm = new Vue({
  el: '#app7-2',
  data: {
    message: '1つしか表示されないはず'
  }
});

// 上から呼ばれるので、#app7-2では使えない
Vue.component('component-name2', {
  // 第２引数：Vueコンポーネント用の書き方色々
  // 今回は簡単にtemplateだけ
  template: '<p>これは表示されないはず</p>'
});
```

*結果*
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/6d185fe1-d094-525f-58f1-c344cd4de610.png)

#### dataは関数にする

Vue.jsの仕様として、コンポーネントの`data`は**関数にする必要がある**。
なぜ関数にする必要があるかというと、仮に`data`がオブジェクトだったとすると全てのインスタンスでdataが共有されてしまうため。
コンポーネント化することで複数のインスタンスを作成することができるようになったが、
そのインスタンスのフィールドの値が全て同じだったら意味がない。
よって、関数にする必要があります。

```sample7-3.html
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app7-3">
  <component-name></component-name>
</div>
```
```sample7-3.js
Vue.component('component-name', {
  // コンポーネントではdataを関数にする
  data: function() {
    return {
      message: 'コンポーネントdata'
    }
  },
  template: '<p>{{message}}</p>'
});

var vm = new Vue({
  el: '#app7-3',
});

```

*結果*
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/2ed929ad-bd8d-dda4-2369-128d27d6013d.png)

### グローバル登録・ローカル登録

`sample7-3.js`のように、Vueコンポーネントを定義したより後ろのVueインスタンス（インスタンス名：vm）で使えるようにする登録方法を**グローバル登録**という。
それに対して、指定したVueインスタンスに直接Vueコンポーネントを定義できる。この登録方法を**ローカル登録**という。


```sample7-4.html
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app7-4-1">
  <!-- ローカル登録のコンポーネント名が勝つ -->
  <component-name></component-name>
</div>
<hr>
<div id="app7-4-2">
  <!-- グローバル登録のコンポーネントが表示される -->
  <component-name></component-name>
</div>
```

```sample7-4.js
// コンポーネントのグローバル登録
Vue.component('component-name', {
  // コンポーネントではdataを関数にする
  data: function() {
    return {
      message: 'グローバル登録'
    }
  },
  template: '<p>{{message}}</p>'
});

// ローカル登録では、コンポーネントを変数で定義する
var component = {
  // コンポーネントではdataを関数にする
  data: function() {
    return {
      message: 'ローカル登録'
    }
  },
  template: '<p>{{message}}</p>'
}

var vm1 = new Vue({
  el: '#app7-4-1',
  // コンポーネントのローカル登録
  components: {
    'component-name' : component
  }
});

var vm2 = new Vue({
  el: '#app7-4-2',
});
```

*結果*
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/cb3001ca-3a4d-0ecb-87e2-7166409b4d01.png)