Vue.js を１から学んでみた。


**Nuxt.jsを使ってみたい！**

いきなりタイトルとは違うところを書きましたが、**Nuxt.jsを使うためにはVue.jsの知識が必要**。

Vue.jsから一から学んでいく時にメモ＋まとめ的につらつらと書いていきます。

誤字や誤認識もあるかと思いますが、その際はご指摘をいただけると非常に助かります:bow::bow::bow:

## 参照したもの

[本家のサイトのガイド](https://jp.vuejs.org/v2/guide/)
[本家のサイトのAPI](https://jp.vuejs.org/v2/api/)

## 準備

簡単に打鍵しながら学びたいので、[jsfiddle](https://jsfiddle.net/)を使ってます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/6c0c9533-c343-b20b-be87-84993ec1f0fa.png)
HTMLとJS簡単に試せます。

詳しい使い方として、こちらのサイトを参考にさせていただきました。
[簡単にコードを実装してシェアできる！超便利なjsFiddleの使い方](https://digitalidentity.co.jp/blog/creative/how-to-jsfiddle.html)

*ちなみに開発時はVSCodeを使ってます。便利なプラグインも多くて助かります。
サーバーサイドも一緒に開発する時にはIntellJです（Kotlin&SpringFramework）。*

## 1.概要

まずは[本家のサイト](https://jp.vuejs.org/v2/guide/) を参考に。

ざっとみて、以下の点か重要かなと。

* テンプレート構文を使って、MVVMしてる
* ディレクティブを使って、DOMにリアクティブ可能。
  * タグの属性に処理を設定できる
  * タグ自体の分岐やループ等の処理もできる
  * イベントハンドラの設定もできる
* コンポーネントシステムを使って、再利用可能な小さい部品を作って使いまわせそう
  * アトミックデザインに適した実装が可能かな？
  * でかいシステムでも、設計をちゃんとすれば複数人数で開発できそう

## 2.Vue定義
### Vueインスタンス

Vueにはフィールドとメソッド等を定義可能。
Javaエンジニアなので、属性と振る舞いという観点で理解しようとする。

* 属性（一部）
  * data
      * Vueインスタンスプロパティの1つ。
      * **ここで定義したものがインスタンス化された時にgetter/setterが用意・監視され、リアクティブを実現している。**
  * el
      * Vueインスタンスを作成後、DOMにマウントするときに指定する
      * もしVueのフィールドに指定しない場合、どこのDOMにもマウントされない。その場合は、`vm.$mount(#app-0)`をコールしてマウントする。
* 振る舞い
  * methods
      * Vue.jsでは**メソッド**と呼ばれる。
      * Vueコンポーネントが少しでも変わったら、実行される。
      * 使いまくるとことある毎に画面が再描画されることもある。**よって、あんまり使わない方が良い**。
      * 引数が無くても()はつけるのが無難。例：`changeMethod()`。
          * `changeMethod`でも書けるけど、どっちかに統一するのが無難。
  * computed
      * Vue.jsでは**算出プロパティ**と呼ばれる。
      * return が必ず必要。特殊なGetterのようなイメージ。
      * レスポンスの内容を毎度キャッシュしており、レスポンスの内容が変わる場合のみ、実行される。
      * 再描画のタイミングが少ない。
      * **methodsよりもこちらを使った方が良い。**
      * **使用頻度が一番高くあるべき**
      * ()はつけちゃだめ。プロパティと呼ばれるだけある。例：`changeComputed`
  * watch
      * Vue.jsでは**ウオッチャ**と呼ばれる。
      * インスタンスフィールドを監視する。
      * 関数名に必ずインスタンスフィールド名を設定する。
      * 非同期処理の実行や、処理のタイミングを制御できる。
      * return は不要というより設定できない。
      * **computedでは対応できないような複雑な実装が必要な場合に使用する。**


Vueインスタンスの作成方法は簡単。ViewModelにあやかって`vm`という変数名をつけることが多いみたい。

```sample0-1.html
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app-0">
  <button v-on:click="changeMethod()">メソッドを実行します</button>
  <p>{{ mehodsStr }}</p>
  <hr>
  <p>{{ changeComputed }}</p>
  <hr>
  <button @click="watchStr = '監視スタート'">ウオッチャを実行します</button>
  <p>{{ watchStr }}</p>
</div>
```

```sample0-1.js
var vm = new Vue({
  // DOMへのマウント定義
  el: '#app-0',
  data: {
    mehodsStr: 'メソッド初期値',
    watchStr: 'ウオッチャ初期値'
  },
  methods:{
    // メソッドが呼ばれるときだけでなく、
    // 再描画されるタイミングに毎回呼ばれる
    changeMethod: function() {
      this.mehodsStr = 'メソッドが実行されました'
    }
  },
  computed:{
    // インスタンス作成時に初回実行され、
    // レスポンスが変わるタイミングでのみ実行される。
    // 今回のパターンは、文字列のハードコードのため、
    // 2度と呼ばれることは無い。
    changeComputed: function() {
      return "算出プロパティ変更後"
    }
  },
  watch: {
    // 非同期処理を実装できる
    watchStr: function () {
      var vm = this;
      setTimeout(function(){
        vm.watchStr = "3秒後に実施されました"
      }, 3000)
    }
  }
})
```

*結果*
![aaa8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/c2a41db5-b9f2-ce33-ae63-c32a7b8924c5.gif)




### Vueインスタンスのライフサイクル

以下が、Vueインスタンスのライフサイクル。

* beforeCreate
  * インスタンスが作られる前。
  * dataにもアクセスできない＝作られていない
* created
  * インスタンスが作られたあと
  * dataのgetter/setterも作られ、リアクティブ状態になる
* beforeMount
  * $elを作ってDOMに追加する前
    * インスタンスに`el`が含まれていない場合：$mount()がコールされる
    * `template`をrender関数でコンパイル＝仮想Nodeを作る
    * 仮想DOMにする前
* mounted
  * 仮想DOMを実際のDOMにマウントされた後
* beforeUpdate
  * 仮想DOMが変わった時に、DOMを再描画する前
* updated
  * 仮想DOMが変わった時に、DOMを再描画した後
* beforeDestroy
  * 破棄する前
* destroyted
  * 破棄した後

Vueインスタンスのライフサイクルをトリガーにフックしたくなる時は以下を参考に。

```sample0-2.js
new Vue({
  data: {
    a: 1
  },
  // createdのフック
  created: function () {
    console.log('a is: ' + this.a)
  }
})
```

![image.png](https://jp.vuejs.org/images/lifecycle.png)

### data

* インスタンスプロパティの一つ。 [全てのインスタンスプロパティはこちら](https://jp.vuejs.org/v2/api/#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3)
* Vueインスタンスを監視しているデータオブジェクト。
* Vueを定義する時のdataは、外部のオブジェクトを指定することも出来る。

```sample2-1.js
var hoge = { a: 1 }

// インスタンスを直接生成
var vm = new Vue({
  data: hoge
})
vm.a // => 1
vm.$data.a // => 1
vm.$data === hoge // => true
```

注意点がいくつかある。

* $dataに設定できるオブジェクトはプレーンなもの。

### template

DOMを置換するのに使用可能。
ハードコードっぽくなりやすいので使いにくいかな。

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

<div id="app-2-2">
<!-- 置き換えられるので、spanは表示されない -->
  <span v-bind:title="message">
    Hover your mouse over me for a few seconds
    to see my dynamically bound title!
  </span>
</div>
```
```sample2-2.js
var app2 = new Vue({
  el: '#app-2-2',
  data: {
    message: 'You loaded this page on ' + new Date().toLocaleString()
  },
  template: '<h1>{{message}}</h1>'
})
```

*結果*

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69626/6926a13b-af6b-345f-66b9-3a9f53422c74.png)

### render

* createElementで仮想Node（**VNode**という）を作って、render関数で仮想DOMを構築してDOM要素を作る*（まだしっくりきていない・・・）*
* createElementは、第一引数をタグ名、第二引数をDOM要素とする

```sample2-2-α.js
var app2 = new Vue({
  el: '#app-2-2',
  data: {
    message: 'You loaded this page on ' + new Date().toLocaleString()
  },
  // template→renderに
  render: function(createElement) {
  	return createElement('h1', this.message)
  }
})
```


## 3.テンプレート構文

もっとも基本的なデータバインディングは、二重中括弧を利用したもの。
この「二重中括弧」、”Mustache（むすたっしゅ）” 構文という。~~初めて知ったけどそれは隠そうと思う。~~

```HTML
<!--Vueインスタンスのmsgフィールドの情報をバインディングする。 -->
<span>Message: {{ msg }}</span>
```
JSでmsgフィールドの内容が変更されたら、上記の内容も変更されます（双方向バインディング）。

ただし、一度表示したらmsgフィールドの内容がかわろうとも、変更されないような書き方もあります。
`v-once`ディレクティブを使います。

```HTML
<span v-once>This will never change: {{ msg }}</span>
```

このように、痒いところに届きそうなものから、すげー使うやつまでディレクティブの種類が多すぎそうなので主要なものと言われるのをまとめてみます。


## 4.ディレクティブ

[ディレクティブについてはこちら](https://qiita.com/sh-watanabe/items/0c095aa74ca54e3dba8c)

## 5.修飾子

[修飾子についてはこちら](https://qiita.com/sh-watanabe/items/0e850d0a2390dc74ee91)

## 6.仮想DOM

仮想Node（VNode）をcreateElement()で作成して、render関数で返すと仮想DOMが作られDOM要素として展開される。
通常、DOMノードに対してアクセスすると処理が遅い。それを解消するための仕組み（と思っている・・・）。
詳細にいうと、仮想DOMで差分を検知したら、実際のDOMノードの差分を更新するという仕組み。

以下の例でいうと、仮想DOMがthis.messageの変更を検知して（このサンプルでは変更されることはないけど・・・）、
実際のDOMノードを変更する。

```sample2-2-α.js
var app2 = new Vue({
  el: '#app-2-2',
  data: {
    message: 'You loaded this page on ' + new Date().toLocaleString()
  },
  // template→renderに
  render: function(createElement) {
  	return createElement('h1', this.message)
  }
})
```

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

[Vueコンポーネントについてはこちら](https://qiita.com/sh-watanabe/items/36863a46e5f80384335c)

## 8.Vue CLIとVue Component

[Vue CLIとVue Componentについてはこちら](https://qiita.com/sh-watanabe/items/f31473b60585ef5f30cc)

## 9.フィルター

[フィルターについてはこちら](https://qiita.com/sh-watanabe/items/72c3082b569cbdae8de6)

## 10.ミックスイン

[ミックスインについてはこちら](https://qiita.com/sh-watanabe/items/073a2082d3fcf4e13810)

## 11.カスタムディレクティブ

[カスタムディレクティブについてはこちら](https://qiita.com/sh-watanabe/items/439d8d7bd527b1a6b394)


## 99.その他

### クラスとスタイルのバインディング
[本家のサイト](https://jp.vuejs.org/v2/guide/class-and-style.html)には、以下の技が載っているのでご参考までに。

* [HTMLクラスのバインディング](https://jp.vuejs.org/v2/guide/class-and-style.html#HTML-%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%AE%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)
   * [オブジェクト構文](https://jp.vuejs.org/v2/guide/class-and-style.html#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%A7%8B%E6%96%87)
      * 例：`<div v-bind:class="{ active: isActive }"></div>`
   * [配列構文](https://jp.vuejs.org/v2/guide/class-and-style.html#%E9%85%8D%E5%88%97%E6%A7%8B%E6%96%87)
      * 例：`<div v-bind:class="[activeClass, errorClass]"></div>`
   * [コンポーネントを使ったバインディング](https://jp.vuejs.org/v2/guide/class-and-style.html#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AB%E3%81%8A%E3%81%84%E3%81%A6)
      * 例：`<my-component v-bind:class="{ active: isActive }"></my-component>`
* [インラインスタイルのバインディング](https://jp.vuejs.org/v2/guide/class-and-style.html#%E3%82%A4%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)
   * [オブジェクト構文](https://jp.vuejs.org/v2/guide/class-and-style.html#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%A7%8B%E6%96%87-1)
      * 例：`<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>`
   * [配列構文](https://jp.vuejs.org/v2/guide/class-and-style.html#%E9%85%8D%E5%88%97%E6%A7%8B%E6%96%87-1)
      * 例：`<div v-bind:style="[baseStyles, overridingStyles]"></div>`

### this.が使えない箇所

基本的には、インスタンスプロパティをそのまま使う様な箇所でしか使えないイメージ。
ユーティリティのようなフィルターや、各要素に対して適用させるようなカスタムディレクトリについては使えなそう。

* カスタムディレクティブでは使えない
* フィルターでは使えない


*※以下、随時追加。*