vue.jsを初めて学ぶ ② [テンプレート構文]

前回までの記事
 ↓ 
[① hello world] (https://qiita.com/uechikohei/items/4e44380848d29bf3fd6a)

目次
---

[1. テンプレート構文とは?](#テンプレート構文とは)

[2. newVueテンプレート解説](#new-vueテンプレート解説)

[3. プロパティの種類](#プロパティの種類)

[4. ディレクティブの種類](#ディレクティブの種類)

[5. v-bindとは？](#v-bindとは)

[6. v-onとは？](#v-onとは)

[7. イベント修飾子とは？](#イベント修飾子とは)

[8. キー修飾子とは?](#キー修飾子とは)

[9. v-modelとは？](#v-modelとは)

[10. computedプロパティとは？](#computedプロパティとは)

[11. watchプロパティとは？](#watchプロパティとは)

[12. thisを理解する](#thisを理解する)

[13. ()括弧の使い方](#括弧の使い方)

[14. classをデータにバインディングする方法(オブジェクトと配列)](#classをデータにバインディングする方法)


<!-- 1 -->
---

# テンプレート構文とは

```text:index.js
new Vue({
    el: '#app',
    data: {
      message: 'Hello World'
    }
```
1. Vue.jsが上記テンプレート構文をロード
2. Vue.jsがhtmlを出力
3. ブラウザがhtmlをロード
4. 私達がブラウザで確認できる

<!-- 2 -->
---

#### new vueテンプレート解説

```text:index.html
<div id = "app">
<!-- [1]文字列を出力 -->
  <p>{{message}}</p>

<!-- [2]和を出力 -->
  <p>{{number + 3}}</p>

<!-- [3]三項演算子 -->
  <p>{{ok ? 'yes' : 'no'}}</p>

<!-- [4]メソッドを出力 -->
  <p>{{ sayHi() }}</p>
</div>
```

```text:index.js 
new Vue({
    el: '#app',
    data: {
<!-- [1]文字列を出力 -->
      message: 'Hello World'

<!-- [2]和を出力 -->
      number: 3

<!-- [3]三項演算子 -->
      ok: true
    }
<!-- [4]メソッドを出力 -->
  methods: {
    sayHi: function() {
     return: 'Hi';
    }
   }
  })
```

[三項演算子とは?](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)
唯一の、3 つのオペランドをとる演算子です。
1. 条件に続いて疑問符 (?)
2. 条件が真値であった場合に実行する式
3. コロン (:) が続く
4. 条件がfalseであった場合に実行する式
が最後に来ます

**注意: javascriptが出力されるのは、単一の式のみ**

<!-- 3 -->
---

# プロパティの種類
#### 1. el
マウント先の要素を指定するブロック

#### 2. data
変数を保持するブロック

#### 3. method
関数を保持するブロック

#### 4. computed
関数を保持するブロック
特徴として、returnを使用して返り値が必要。
そして、依存関係に基づきキャッシュされる。

#### 5. watch
関数を保持するブロック
特徴として、returnを使用しないため非同期処理を記述できる

<!-- 4 -->
---

#ディレクティブの種類
- ディレクティブとは、**v-から始まるVue.jsの特別な属性**
- 属性とは、htmlでは**href,class,id**といった要素
[HTMLにおける、属性とは](https://qiita.com/imaizume/items/30ac40933f3453586ffc)

#### 1. v-text

#### 2. v-once

#### 3. v-html　（[xss脆弱性に注意](https://jp.vuejs.org/v2/guide/security.html)）

　対応：信頼のあるコンテンツしか置かないようにする。

#### 4. v-bind

　1. href
　2. class
　3. id
　<br>属性を与える事ができる

### <font color="Red">5. v-on</font>

　使用頻度が多い、DOMイベントを引数として発火する。
　様々な関数を、起動させることが可能。

#### 6. v-model

　双方向データバインディングが可能

<!-- 5 -->
---

# v-bindとは
**属性を与える事ができる**

```text:index.html
<div id = "app">
    <a href="url">Google</a>
</div>
```

```text:index.js
new Vue ({
  data: {
    url: 'https://google.com',
  }
})
```
Vueテンプレートで、url属性を与えようとする。。。
**<font color="Red">404エラーとなってしまう。</font>**

---

**<font color="Blue">v-bind使用例<font>**

```text:index.html
<div id = "app">
    <a v-bind:href="url">Google</a>
</div>
```

```text:index.js
new Vue ({
  data: {
    url: 'https://google.com',
  }
})
```

**<font color="Green">v-bind省略記法</font>**

```text:index.html
<div id = "app">
    <a :href="url">Google</a>
</div>
```

```text:index.js
new Vue ({
  data: {
    url: 'https://google.com',
  }
})
```

**<font color="Green">v-onディレクティブ省略記法</font>**
- v-onを省略する。

```text:index.html
    <p>現在{{number}}回クリックされています</p>
    <button @click="countUp">countUp</button>
```

<font color="red">**省略が可能な記法(:や@)は、プロジェクト内で統一する。**</font>


### v-bindを <font color="red">オブジェクト化</font> して使用する。
1. hrefリンク
2. class
3. id
<br>複数の属性を与えたい時、 <font color="red">**オブジェクト化**</font> が最適

<font color="green">**方法**</font> 

```text:index.html
<div id = "app">
    <a v-bind="objectGoogle">Google</a>
</div>
```

```text:index.js
new Vue ({
  data: {
    objectGoogle: {
      href: 'https://google.com',
      class: 'sample',
      id: 31
    }
  }
})
```

**chromeブラウザの「検証」より、v-bindで属性が与えられているのが確認できる**
![スクリーンショット 2020-10-27 13.40.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449720/5f0c7f8e-f771-c5dd-ab73-85a37350151f.png)

<!-- 6 -->
---

# v-onとは
<font color="red">**DOMイベントが発火するタイミングで、実装した関数を実行できる**<font>

[DOMイベントとは？(一覧)](https://developer.mozilla.org/ja/docs/Web/Events)

## ボタンクリックで数字がカウントされる処理を実装してみる。
**v-on:に指定するのは、<font color="green">clickイベント**</font>

```text:index.html
<div id = "app">
    <p>現在{{number}}回クリックされている</p>
    <button v-on:click="countUp">カウントアップ</button>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      data: {
        number: 0
      },
      methods: {
        countUp: function() {
          this.number += 1
        }
      }
    })
```
1. clickイベントが発火する
2. countUp関数が起動 ( 変数numberに、+1 )
3. {{ number }} に反映


## マウスをかざした場所の、XY軸を表示する
**v-on:に指定するのは、<font color="green">mousemoveイベント**</font>

```text:index.html
<div id = "app">
    <p v-on:mousemove="changeMousePosition">マウスを載せてください</p>
    <p>X:{{x}},Y{{y}}</p>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      data: {
        x:0,
        y:0,
      },
      methods: {
        changeMousePosition: function(event) {
          this.x = event.clientX;
          this.y = event.clientY;
        }
      }
    })
```

**DOMイベントの情報を拾うには、ルールがある**
1. 引数にはeventを文字として使用。他でも格納できるがよっぽど理由がなければ変更しない。
2. 格納したeventから読み取る事。

<!-- 7 -->
---

# イベント修飾子とは
1. 従来のstopPropagationを、<font color="red">**stop**</font> で実装可能
2. 従来のpreventDefaultを、<font color="red">**prevent**</font> で実装可能


## 処理をSTOPさせる

**従来のstopPropagation**

```text:index.html
<div id = "app">
    <p v-on:mousemove="changeMousePosition">マウスをかざしてください
      <span v-on:mousemove="noEvent">マウスをかざしても反応させない。</span>
    </p>
    <p>X:{{x}},Y{{y}}</p>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      data: {
        x:0,
        y:0,
      },
      methods: {
        changeMousePosition: function(event) {
          this.x = event.clientX;
          this.y = event.clientY;
        },
        noEvent: function(event) {
          event.stopPropagation()
      }
    })
```
1. spanタグにnoEvent関数を追加
2. noEvent関数に、stopPropagationという処理をstopさせる命令を追加


## Vue.jsのすごい所
- <font color="red">**v-on:mousemove.stopを与えるのみ！**</font>

```text:index.html
<div id = "app">
    <p v-on:mousemove="changeMousePosition">マウスをかざしてください
      <span v-on:mousemove.stop>マウスをかざしても反応させない。</span>
    </p>
    <p>X{{x}},Y{{y}}</p>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      data: {
        x:0,
        y:0,
      },
      methods: {
        changeMousePosition: function(event) {
          this.x = event.clientX;
          this.y = event.clientY;
        }
    })
```


## 処理をpreventさせる
- preventとは、html側のデフォルト設定までも起動させない

## <a href>リンクタグをクリック、飛ばないように設定。
**従来のpreventDefault**

```text:index.html
<div id = "app">
    <a v-on:click="noEvent" href="https://google.com">google.com</a>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      methods: {
        noEvent: function(event) {
          event.preventDefault();
       }
    })
```

## Vue.jsのすごい所
- <font color="red">**html側に、v-on:mousemov.preventを与えるのみ！**</font>

```text:index.html
<div id = "app">
    <a v-on:click.prevent href="https://google.com">google.com</a>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
    })
```

#### stopとpreventを、つなげる事も可能
`v-on:mousemove.stop.prevent`

<!-- 8 -->
---

# キー修飾子とは
**キーボード入力イベントに対する修飾子**
1. エンターキーを入力時点で動作させる。`.enter`
2. スペースキー入力時点で動作させる。`.space`


```text:index.html
<div id = "app">
    <input type="text" v-on:keyup.enter="myAlert">
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      methods: {
        myAlert() {
          alert('アラート');
        }
      }
    })
```

つなげる事も可能
`v-on:keyup.enter.space`

<!-- 9 -->
---

# v-modelとは

**双方向データバインディング**
1. inputにテキストを入力
2. 変数messageの内容が置き換わる。
3. data内のmessageが置き換わる。
4. h1タグのmessageも変更される。

```text:index.html
<div id = "app">
    <input type="text" v-model="message">
    <h1>{{message}}</h1>
  </div>
```

```text:index.js
new Vue ({
      el: '#app',
      data: {
        message: 'こんにちは',
      }
    })
```


<!-- 10 -->
---

# computedプロパティとは

- **dataプロパティ**では、<font color="red">動的なデータは扱えない。</font>(プレーンなテキストのみ)
- **computedプロパティ**を使用する

```text:index.html
<div id = "app">
    <p>{{ counter }}</p>
    <button v-on:click="countUp">+1</button>
    <p>{{ lessThanThree }}</p>
</div>
```

```text:index.js
new Vue ({
      el: '#app',
      data: {
        counter: 0
      },
      methods: {
        countUp: function() {
          this.counter += 1
        }
      },
      computed: {
        lessThanThree: function() {
          return this.counter > 3 ? '3より上' : '３以下'
        }
      }
    })
```

**computedプロパティの関数、lessThanThreeには**

- 引数が必要ではない
- **return**で値を返す必要がある

関数lessThanThreeは、<br><font color="green">methodsプロパティでは実現できないのか？</font>
--- 

# 結論：<br><font color="blue">できるけど、、<br>最適化するならComputedメソッド一択！</font>
- **computedプロパティ**は<font color="green">**依存関係に基づきキャッシュされる**</dont>特徴がある。
- **methodsプロパティ**は、全く関係のないメソッドの更新にも反応する。
- 大規模になると、methodsプロパティで記述した関数が無駄に実行されてしまう。

```text:index.html
  <div id = "app">
    <p>{{ counter }}</p>
    <button v-on:click="countUp">+1</button>
    <p>{{ lessThanThreeMethod() }}</p>
    <p>{{ lessThanThreeComputed }}</p>
  </div>
```

```text:index.js
    new Vue ({
      el: '#app',
      data: {
        counter: 0
      },
      methods: {
        countUp: function() {
          this.counter += 1
        },
        lessThanThreeMethod: function() {
          return this.counter > 3 ? '3より上' : '３以下'
        }
      },
      computed: {
        lessThanThreeComputed: function() {
          return this.counter > 3 ? '3より上' : '３以下'
        }
      }
    })
```


<!-- 11 -->
---

# watchプロパティとは

- データが変わったとき、<font color="red">**非同期処理**</font> が実行
- 非同期処理の中では、<font color="red">**thisが使用不可**</font>
- computedプロパティでは、returnが必要（同期処理）になる。
- 非同期処理したい場合はwatchプロパティが最適。

## 3秒でカウントの値(counter)が0にリセットされる非同期処理

```text:index.html
  <div id = "app">
    <p>{{ counter }}</p>
    <button v-on:click="countUp">+1</button>
    <p>{{ lessThanThreeComputed }}</p>
  </div>
```

```text:index.js
    new Vue ({
      el: '#app',
      data: {
        counter: 0
      },
      methods: {
        countUp: function() {
          this.counter += 1
        }
      },
      computed: {
        lessThanThreeComputed: function() {
          return this.counter > 3 ? '3より上' : '３以下'
        }
      },
      watch: {
        counter: function() {
          var vm = this;
          setTimeout(function(){
            vm.counter = 0
          }, 3000)
        }
      }
    })
```


<!-- 12 -->
--- 

# thisを理解する。

## 変数messageを、 関数sayHi内で 呼び出してみる。

```text:index.js
new Vue({
  el: '#app',
  data: {
    message: 'Hello,World!!'
},
methods: {
  sayHi: function() {
<!--これはエラーになる-->
      return message;
<!--正しくは、thisが必要-->
      return this.message;
    }
  }
})
```

```text:index.html
<div id = "app">
  <p>{{ sayHi() }}</p>
</div>
```

**thisとは、<br><font color="red">Vue.jsのインスタンスにアクセスするために必要なプロキシ**
</font>


<!-- 13 -->
---

# 括弧の使い方

- **computedプロパティでは、メソッド名のみを{{二重カッコ内}}に記載**
  computedプロパティに()を足すと、エラーとなり表示されなくなる。

- **methodsプロパティでは、メソッド名+()を{{二重カッコ内}}に記載**
  methodプロパティから（）を除くと、<br>`function () { [native code] }`と表示される。

- v-ディレクティブの引数としてメソッド名を指定する場合
　（）は付与してもしなくてもどちらでもOK。
  引数には、javascriptコードを書いてもOK。

<!-- 14 -->
--- 

# classをデータにバインディングする方法

## { オブジェクト }で記載

- ハイフンの記載がオブジェクト内にある場合、'bg-color'とシングルクォーテーションで括る必要あり。


```text:index.html
  <div id = "app">
    <h1 :class="{red: true, 'bg-blue': false}">はろう</h1>
  </div>
```

```text:index.js
    new Vue ({
      el: '#app'
})
```

```text:sample.css
.red {
  color: red;
}

.bg-blue {
  background-color: blue;
}
```

**ボタンを設置して、クラスの付与を分岐する。**

```text:index.html
  <div id = "app">
    <h1 :class="classObject">はろう</h1>
    <button @click="isActive = !isActive">切り替えボタン</button>
  </div>
```

```text:index.js
    new Vue ({
      el: '#app',
      data: {
        isActive: true
      },
      computed: {
        classObject: function() {
          return {
            red: this.isActive,
            'bg-blue': !this.isActive
          }
        }
      }
    })
```

```text:sample.css
.red {
  color: red;
}

.bg-blue {
  background-color: blue;
}
```


# [ 配列 ] で記載

```text:index.html
  <div id = "app">
    <h1 :class="[color, bg]">はろう</h1>
  </div>
```

```text:index.js
    new Vue ({
      el: '#app',
      data: {
        color: 'red',
        bg: 'bg-blue',
      }
    })
```

```text.sample.css
.red {
  color: red;
}

.bg-blue {
  background-color: blue;
}
```