Vue.js ザックリ全体を理解しよう！

Vue.jsを勉強し始めの人＆これから勉強しようと思っている人向けに、
Vue.jsについてザックリ全体を説明したいと思います。


:pencil: もくじ
1. [Vue.jsって何？](#vuejsって何)
2. [Vue.jsの書き方](#vuejsの書き方)
3. [状態管理の方法](#状態管理の方法)
4. [ディレクティブ](#ディレクティブ)
5. [親子コンポーネント間でのデータ共有方法(props/emit)](#親子コンポーネント間でのデータ共有方法propsemit)
6. [ライフサイクルフック](#ライフサイクルフック)

---

# Vue.jsって何？
元Googleのエンジニア・Evan You(エヴァン・ヨー) さんにによって開発され、2014年2月にリリースされました。
[公式ページ](https://vuejs.org/)

Vue.jsとは、**UI作成のためのプログレッシブなJavaScriptフレームワーク** です。
フレームワークの中には、それ自身がオーバースペックすぎるものもあり、機能がToo muchだったり複雑だったりと学習コストも高くなってしまいます。
それに比べて、Vue.jsは最低限の機能はコア部分のみをVue.jsに搭載しており、それ以外の機能は別のライブラリとして色々と用意されています。
**最初に開発を始めるときは小さく、必要に応じて（アプリケーションが大規模になるにつれて）適切なライブラリを適宜導入していこう**、という考えでできています。
これが「プログレッシブ」なフレームワーク、ということなんですね。
エヴァンさんがVueを作るきっかけになったというストーリーにも関連しています。

参考：
[FIRST WEEK OF LAUNCHING VUE.JS](https://blog.evanyou.me/2014/02/11/first-week-of-launching-an-oss-project/)
[Customer story ~Evan You~](https://github.com/customer-stories/yyx990803)


# Vue.jsの書き方
Vue.jsにはいくつか書き方があるのですが、
単一ファイルコンポーネントでの書き方がおすすめです！

他の書き方よりも、単一ファイルコンポーネントがおすすめな理由はこちらの[公式サイト](https://jp.vuejs.org/v2/guide/single-file-components.html)を読んでいただくとして・・・

## 単一ファイルコンポーネントとは
単一ファイルコンポーネントとは、1つのコンポーネントに
**HTML(templateタグ)**、 **JavaScript(scriptタグ)**、 **CSS(styleタグ)**
をひとまとめに定義したファイルです。（拡張子は `.vue` ）

※分割された各コンポーネント（.vueファイル）を結合するためには、Webpackのようなバンドルツールが必要になります。

それでは１つずつ見ていきましょう。

### templateタグ
- HTML を記載する
- JavaScriptの変数やメソッドを挿入させる場合は{{ .. }} で囲う
- 他のコンポーネントも利用可
    - セルフクロージングタグ or 閉じタグが必要
    - 子コンポーネントにプロパティを渡すことができる
    - 変数を渡したい場合は、v-bind を使う

```vue
<template>
 <div id="app">
   <h1>{{ greeting }}</h1>
   <Nav v-bind:title=”title” />
 </div>
</template>
```

### scriptタグ
- JavaScriptを記載する
- 他のコンポーネントやファイルをimportする場合は、scriptタグの先頭に記載する
- その他のさまざまなプロパティを記載する
    - name：コンポーネント名を定義
    - components：importしたコンポーネントを登録
    - data：コンポーネント内の状態(state)を管理
    - props：親コンポーネントから渡されたデータを受け取る
    - methods：コンポーネント内で使用することのできるメソッドを定義
    - ...

```vue
<script>
import Navbar from "./Navbar";
export default {
 name: "App",
 components: {
   Nav: Navbar
 },
 data(){
   return {
     greeting: "Welcome!!",
     title: "home",
   };
 },
};
</script>
```

### styleタグ
- CSS を記載する
- `scoped`を付けると、そのコンポーネント内でのみスタイルが適用される
    - 付けなければ全コンポーネントに適用される
- `scoped`付きのスタイルと無しのスタイルを同一コンポーネントに記載可能
- 書き方は通常のCSSファイルと同じ


```vue
<style scoped>
 /* local styles */
 #app {
  text-align: center;
 }
</style>

<style>
 /* global styles */
</style>
```


# 状態管理の方法
scriptタグの`data`でコンポーネント内の状態(state)を管理します。

下記のサンプルでは、`count` という変数に初期値0を定義しており、
ブラウザで開いた時は `You clicked me 0 times.` と表示され、
ボタンをクリックするたびに数字がインクリメントされる、という動きになります。

```Counter.vue
<template>
<button v-on:click="count++">
  You clicked me {{ count }} times.
</button>

</template>

<script>
export default {
 name: "Counter",
 data: function() {
   return {
     count: 0
   }
 },
};
</script>
```

ちなみに、dataは関数として定義しなければならないので注意です！
↓こういう書き方はNG!!

```
data: {
  count: 0
}
```
公式サイトの[よくある初心者の落とし穴](https://jp.vuejs.org/2016/02/06/common-gotchas/#%E3%81%AA%E3%81%9C-data-%E3%81%AF%E9%96%A2%E6%95%B0%E3%81%A8%E3%81%97%E3%81%A6%E5%BF%85%E8%A6%81%E3%81%AA%E3%81%AE%E3%81%A7%E3%81%99%E3%81%8B%EF%BC%9F)のページにも説明が載っていますので、よくわかっていない人は是非読んでみてください。



# ディレクティブ
ディレクティブとは、`v-`から始まる特別な属性(attribute)です。

属性というキーワードにいまいちピンと来ない人もいるかもしれませんが、
例えばHTMLで言うと「divタグの`class属性`」「aタグの`href属性`」という言い方をしますが、
このようにそのタグに補足的な情報を与えるものを`属性`と呼びます。

```html
<div class="sample">こんにちは</div>
<a href="http...">リンク先はこちら</a>
```

Vue.js では下記のような書き方をしますが、
この場合 `show`の値(true/false)に基づいて h1タグを挿入/削除します。

```html
<h1 v-if="show">You can see me!</h1>
```

他にもいろんな種類のディレクティブがありますので、よろしければ下記の公式サイトのページをご覧ください。
[公式サイト・ディレクティブの種類](https://jp.vuejs.org/v2/api/#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96)


# 親子コンポーネント間でのデータ共有方法(props/emit)
コンポーネント間でデータの受け渡しを行う場合は、
下記図のように、親子コンポーネント間でバケツリレーのような形で渡す必要があります。
![Screen Shot 2020-01-28 at 22.03.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/40069634-5e74-effc-db94-4310a6d728d9.png)
※この図は[こちら](https://vuex.vuejs.org/ja/)の動画で使われていたスライドを拝借させていただきました。

## 親→子コンポーネント
- 親からv-bindでデータを渡す
- 子はpropsでデータを受け取る

下記の例を見てみましょう！

#### 親コンポーネント（子コンポーネントにデータを渡す）
`child`という子コンポーネントに、
v-bind(省略記号はコロン(:))を使って`name`と`image`のデータを渡します。


```vuejs
<template>
 <div>
  <div v-for="prof in profiles" :key="prof.name">
    <child
      :name="prof.name"
      :image="prof.image"
    />
  </div>
 </div>
</template>
```

#### 子コンポーネント（親コンポーネントからデータを受け取る）
親コンポーネントから渡されたデータ(`name`と`image`)は、
scriptタグ内の`props`で受け取ることができます。

下記では、imgタグのsrc属性の値に`image`を使用し、h2タグに`name`を表示しています。

```vuejs
<template>
 <div class="profile">
   <img :src="image" />
   <h2>{{ name }}</h2>
 </div>
</template>

<script>
export default {
 name: "Child",
 props: [ "name", "image" ],
};
</script>
```

**〜上記プログラムの流れ〜**
1. 親コンポーネント：子コンポーネントタグ内で`name`と`image`をv-bindし、子にデータを渡す
2. 子コンポーネント：親コンポーネントから渡されたデータを`props`で受け取る
3. 子コンポーネント：imgタグのsrc属性の値に`image`を使用し、h2タグに`name`を表示


## 子→親コンポーネント
- 子はemitでイベントを発火
- 親は子のイベントを監視し、イベントが発火されたら処理を実行

下記の例を見てみましょう！

#### 親コンポーネント（子コンポーネントからのイベントを監視）
templateタグ内で`child`という子コンポーネントを呼び出し、v-on(省略記号は@)で子からのイベントを監視しています。
`childBtnClick`のイベントが発火されたら`showMsg`のメソッドを呼び、
そこでは引数として子から渡された文字列「`Click!`」を受け取ることができます。

```vuejs
<template>
 <div id="app">
   <child @childBtnClick="showMsg" />
   <p>{{ msg }}</p>
 </div>
</template>

<script>
import Child from "./components/Child";
export default {
 name: "App",
 data:() => ({
   msg: “”,
 }),
 components: {
   child: Child
 },
 methods: {
   showMsg: function(msg) {
     this.msg = msg;
   }
 }
};
</script>
```

#### 子コンポーネント（emitを使って、親コンポーネントにイベントを送る）
`$emit`を使うと、親にイベントをを送ることができます。
`$emit`の第一引数には親に送るイベント名を、第二引数以降には親に渡したいデータを指定することができます。（第二引数以降は任意指定）

ボタンがクリックされたら`clickBtn`メソッドが呼び、
`$emit`を使って親に`childBtnClick`のイベントを送り、引数として`Click!`の文字列を渡しています。

```vuejs
<template>
 <div>
   <button @click="clickBtn">Show!</button>
 </div>
</template>

<script>
export default {
 name: "Child",
 methods: {
   clickBtn() {
     this.$emit("childBtnClick", "Click!");
   }
 }
};
</script>
```

**〜上記プログラムの流れ〜**
1. 親コンポーネント：子コンポーネントからの`childBtnClick`のイベントを監視
2. 子コンポーネント：ボタンがクリックされたら`clickBtn`メソッドを呼ぶ
3. 子コンポーネント：`$emit`を使って親に`childBtnClick`のイベント・`Click!`の文字列を渡す
4. 親コンポーネント：子コンポーネントからの`childBtnClick`イベントの発火を検知したので、`showMsg`メソッドを呼ぶ
5. 親コンポーネント：`showMsg`メソッド内で、子から渡された文字列「`Click!`」を受け取り、変数`msg`に代入
6. 親コンポーネント：pタグの文字が`Click!`に変わる


※ [Vuex](https://vuex.vuejs.org/ja/)とは、 Vue.jsアプリケーションのための 状態管理ライブラリです。
Vuexで状態を一元管理することができるので、上記のようにコンポーネント間でバケツリレーのようなデータ受け渡しをする必要がなくなり、とてもシンプルに状態を扱うことができます。




# ライフサイクルフック
Vue.jsには、インスタンスの生成〜破棄までの状態の変化(ライフサイクル)により発火する様々な関数（ライフサイクルフック）が用意されており、コンポーネントの状態に応じて色々な操作ができるようになっています。

| ライフサイクルフック | 説明              |
|:-----------------|:------------------|
| beforeCreate     | インスタンス初期化時に実行される。プロパティ(dataなど)は生成前のためアクセスできない。 |
| created          | インスタンス作後に実行される。プロパティへのアクセスが可能になる。 |
| beforeMount      | マウント前に実行される。この時点ではDOM要素にはアクセスできず、ディレクティブなども実行前。 |
| mounted          | マウント後に実行される。この時点でDOM要素へのアクセスが可能になる。ただし、全ての子コンポーネントがマウントされていることは保証されていない。 |
| beforeUpdate     | データが変更される時、DOM更新前に実行される。例）v-ifで要素を消した場合など。 |
| update           | DOM更新後に実行される。ただし、全ての子コンポーネントも再レンダリングが完了していることは保証されていない。|
| beforeDestroy    | Vueインスタンスが破棄される直前に実行される。この時点ではプロパティへのアクセスが可能。 |
| destroyed        | インスタンスが破棄された後に実行される。この時点からプロパティへのアクセスができない。 |

詳しくは、下記の公式サイトを確認してください。
- [ライフサイクルフックの種類](https://jp.vuejs.org/v2/api/#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3-%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%95%E3%83%83%E3%82%AF)
- [ライフサイクルダイアグラム](https://jp.vuejs.org/v2/guide/instance.html#%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%80%E3%82%A4%E3%82%A2%E3%82%B0%E3%83%A9%E3%83%A0)


# さいごに
Vue.jsの公式ドキュメントはとてもしっかり整備されています。
日本語化もされているので、何かわからないことがあったりつまづいたりした時には積極的に公式ドキュメントを見るようにしましょう！

公式ドキュメント：https://jp.vuejs.org/