Vue.js入門 3章 コンポーネントの基礎（コンポーネントとは何か／Vueコンポーネントの定義）

前 [Vue.js入門 2章 Vue.jsの入門（ライフサイクルフック／メソッド）](https://qiita.com/tseno/items/3e2a8004de47daac4eb2)
次 [Vue.js入門 3章 コンポーネントの基礎（コンポーネント間の通信／スロットコンテンツ／ログインフォーム）](https://qiita.com/tseno/items/ddb5142f74bae3aa111a)

# コンポーネントとは何か

## 全てはUIコンポーネントから構成される

- 全体がUIコンポーネントの木構造になっている。
- 同等のUIコンポーネントが繰り返し使用されている。
- 柔軟に再利用できるライブラリやフレームワークの導入がWebフロントエンド開発に役に立つ。

## コンポーネント化のメリットと注意点

- 再利用性が高まり、開発効率を上げられる。
- 既に使用されているコンポーネントを再利用することで、品質を保てる。
- コンポーネントを適切に区切り、疎結合にすることで保守性が高まる。
- カプセル化されて、開発で意識すべき範囲を限定できるようになる。

## Vue.jsのコンポーネントシステム

- Vue.jsは小さく、自己完結し、多くの場合再利用可能といったコンポーネントを組み合わせてアプリケーションを設計する。
- 以下の、`Vue.component()`の第一引数にコンポーネント名、第二引数にコンポーネントの内容を与えれば、コンポーネントの完成。

```js
Vue.component('list-item', {
  template: '<li>foo</li>'
})
```

- コンポーネント名をHTMLタグ名として記載するだけで、コンポーネントの内容を流し込める。（カスタムタグ）

```html
<script src="https://unpkg.com/vue@2.5.17"></script>

<ul id="example">
  <list-item></list-item>
</ul>

<script>
Vue.component('list-item', {
  template: '<li>foo</li>'
})

new Vue({ el:'#example' })
</script>
```

### Vueコンポーネントは再利用可能なVueインスタンス

- Vueコンポーネントの中で、テンプレート構文も使える。

```html
<script src="https://unpkg.com/vue@2.5.17"></script>

<ul id="example">
  <list-item></list-item>
</ul>

<script>
Vue.component('list-item', {
  template: '<li>foo{{ contents }}</li>',
  data: function() {
    return {contents: 'bar'}
  }
})

new Vue({ el:'#example' })
</script>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/0cb7d55a-6e72-cf26-4a6b-99d3434bca85.png)


# Vueコンポーネントの定義

- 定義の方法は以下の2つがある
    - Vue.component()を使ったカスタムタグ方式（基本はこちらを使う）
    - Vue.extend()を使ったサブコントラクタ方式（プログラムでコンポーネントのマウントを制御したいとき）

## グローバルコンポーネントの定義

- グローバルコンポーネントをカスタムタグベースで定義する。
- 第一引数・・・コンポーネント名
- 第二引数・・・コンポーネントの構成情報を持ったオブジェクト

```js
Vue.component(tagName, options)
```

|オプション名|用途|
|:--|:--|
|data|UIの状態・データ|
|filters|データを整形する|
|methods|イベントが発生した時などの振る舞い|
|computed|データから派生されて算出される値|
|template|コンポーネントのテンプレート|
|props|親から子へのデータの受け渡し|
|created他|ライフサイクルフック（作成時）|

### シンプルなコンポーネントの実装

```vue
<script src="https://unpkg.com/vue@2.5.17"></script>

<div id="fruits-list">
  <fruits-list-title></fruits-list-title>
</div>

<script>
Vue.component('fruits-list-title', {
  template: '<h1>フルーツ一覧</h1>',
})

new Vue({ el:'#fruits-list' })
</script>
```

### コンポーネントの親と子

- コンポーネントを利用する側が親、利用される側が子という関係が成立する。

```vue
<script>
// 子
Vue.component('fruits-list-title', {
  template: '<h1>フルーツ一覧</h1>',
})
// 親
Vue.component('fruits-list', {
  template: '<div><fruits-list-title></fruits-list-title></div>',
})
</script>
```

## コンストラクタベースの定義（Vue.extend()）

- Vue.extend()というグローバルなAPIを使用して、ベースのVueコンストラクタを継承したサブクラスコンストラクタを作成できる。これを用いてもコンポーネントを作成できる。

```vue
var FruitsListTitle = Vue.extend({
  template: '<h1>フルーツ一覧</h1>'
})

new FruitsListTitle().$mount('#fruits-list')
```

## ローカルコンポーネントの定義

- グローバルに何かを登録するのは、トラブルやコードの複雑化の元になる。そのために、コンポーネントの中でしか使えないローカルコンポーネントを使う。
- `fruits-list`内でしか、`fruits-list-title`は使えない。
- ローカルコンポーネントの定義には、コンストラクタベースのテンプレートも使用できる。

```vue
<script src="https://unpkg.com/vue@2.5.17"></script>

<div id="fruits-list">
  <fruits-list-title></fruits-list-title>
</div>

<script>
new Vue({
  el: '#fruits-list',
  components: {
    'fruits-list-title': {
      template: '<h1>フルーツ一覧</h1>'
    }
  }
})
</script>
```

## テンプレートを構築するその他の手段

- テンプレートを定義する様々方法がある。主に以下の5つ。
    - text/x-template
    - インラインテンプレート
    - 描画関数
    - JSX
    - 単一ファイルコンポーネント

### text/x-template

- `text/x-template`をtypeとして定義したscript要素の中にテンプレートのHTML要素を記述する。
- 記述をHTML側に分割できるので、読みやすい。
- `text/x-template`はブラウザが認識できないMIMEたぷなので、このscript要素は無視される。

```vue
<script type="text/x-template" id="fruits-list-title">
  <h1>フルーツ一覧</h1>
</script>
<script>
Vue.component('fruits-list-title', {
  template: '#fruits-list-title'
})
</script>
```

### 描画関数

- renderオプションを使うことにより、プログラムで記述できる。
- 以下は、今日の日付をinputタグのtype="date"に表示する。

```vue
<script src="https://unpkg.com/vue@2.5.17"></script>

<div id="app">
  <input-date-with-today></input-date-with-today>
</div>

<script>
Vue.component('input-date-with-today', {
  render: function (createElement) {
    return createElement(
      'input',
      {
        attrs: {
          type: 'date',
          value: new Date().toISOString().substring(0,10)
        }
      }
    )
  }
})

new Vue({ el:'#app' })
</script>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/73314f09-c96c-b05e-bed8-99686dc49cb9.png)

### コンポーネントの命名規則について

- ケバブケース（`kebab-fruits-list`）とパスカルケース（`PascalFruitsList`）が使えるが、ケバブケースを推奨。

## コンポーネントのライフサイクル

- コンポーネントはライフサイクルを持っている。Vueインスタンスと同じようにライフサイクルフックを持っている。同じようにイベントに対してフック関数を定義できる。

## コンポーネントのデータ

- コンポーネントが持つデータをdataオプションで定義できる。Vueコンポーネントでは、dataは関数で定義する。
- コンポーネントインスタンスごとに異なるdataオブジェクトを定義したいとき、コンポーネントの中のdataはオブジェクトを返す関数にする。それぞれのコンポーネントごとに状態を持てる。

```js
Vue.component('sample-counter', {
  template: '<h1>フルーツ一覧</h1>',
  data: function() {
    return {
      fruits: ['りんご', 'みかん']
    }
  }
})

```



参考
[Vue.js入門 基礎から実践アプリケーション開発まで](https://www.amazon.co.jp/dp/B07J6FP6NQ/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)