Vue.js入門 2章 Vue.jsの入門（ディレクティブ）

前 [Vue.js入門 2章 Vue.jsの入門（テンプレート、フィルタ、算出プロパティ）](https://qiita.com/tseno/items/387164d8e6c4c59a5136)
次 [Vue.js入門 2章 Vue.jsの入門（ライフサイクルフック／メソッド）](https://qiita.com/tseno/items/3e2a8004de47daac4eb2)

# ディレクティブ

- 標準のHTMLに対して独自の属性を追加することで、属性値の式の変化に応じたDOM操作を行う。この特別な属性をディレクティブと言う。
- Vueインスタンスをマウントした要素と、その子孫でしか使えない。
- ディレクティブの属性値には、JavaScriptの式を与える。データや算出プロパティも使える。

## 条件付きレンダリング（v-if/v-show）

- テンプレート中の要素の表示・非表示を切り替えるのに、v-ifまたはv-showディレクティブを使う。
- いずれも、真の場合は表示、偽の場合は非表示にする。
- 頻繁に式の評価結果が変わる場合は、v-showを使う。

```html
<p v-show="引数">
  // 真の場合は表示、偽の場合は非表示
</p>
```

- ほとんど変わらない場合は、v-ifを使う。

```html
<p v-if="引数">
  // 真の場合は表示、偽の場合は非表示
</p>
```

### サンプルアプリケーションでの実装

- `v-show`に!canBuyを引数として入れる。

```html
  <p v-show="!canBuy">
  　{{ 1000 | numberWithDelimiter }}円以上からご購入いただけます
  </p>
```

- 算出プロパティに、`canBuy`を追加する。

```js
  computed: {
    canBuy: function () {
      return this.totalPrice >= 1000 // 1000円以上から購入可能にする
    }
  }
```

- 1000円未満の時

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/cfd21e97-119e-c6fc-e846-9279f93d0468.png)

- consoleから100個に変更で、「1000円以上から購入いただけます」が消えたことを確認。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/f3e4a037-e2df-1757-0983-e2c86e1c370f.png)

## クラスとスタイルのバインディング

- v-bindはクラスやスタイルを買いたいときに使われるディレクティブ。

```
v-bind:属性名="データを展開した属性値"

v-bind:class="オブジェクト・配列"
v-bind:style="オブジェクト・配列"
```

### クラスのバインディング（v-bind:class）

- trueのプロパティ名がclass名になる。以下は、sharkがclass名になる。

```html
<p v-bind:class="{shark: true, mecha: false}"></p>
```

- canBuyがfalseの時、class名はerrorになる。

```html
<p v-bind:class="{error: !canBuy}">1000円以上から購入いただけます</p>
```

- 算出プロパティを使った例。上記と同じようにcanBuyがfalseの時、class名はerrorになる。

```js
  computed: {
    errorMessageClass: function () {
      return {
        error: !this.canBuy
      }
    }
  }
```

```html
<p v-bind:class="errorMessageClass">1000円以上から購入いただけます</p>
```

### スタイルのバインディング（v-bind:style）

- オブジェクトのプロパティがスタイルのプロパティに対応する。

```html
<p v-bind:style="{color: red}">a</p>
↓
<p style="color: red;">a</p>
```

- 式と組み合わせて使うことができる。

```html
<p v-bind:style="{border: (canBuy ? '' : '1px solid red'), color: (canBuy ? '' : 'red')}">
1000円以上から購入いただけます
</p>
```

- 算出プロパティを使った例。

```js
  computed: {
    errorMessageStyle: function () {
      return {
        border: this.canBuy ? '' : '1px solid red',
        color: this.canBuy ? '' : 'red'
      }
    }
  }
```

```html
<p v-bind:style="errorMessageStyle">1000円以上から購入いただけます</p>
```

### v-bindの省略記法

- 「v-bind:属性名」の省略記法は「:属性名」。コロンを属性値につけるだけ。

```html
<p :class="{error: !canBuy}">1000円以上から購入いただけます</p>
```

### スタイルのバインディングのサンプルへの適用

- スタイルのバインディング

```html
<script src="https://unpkg.com/vue@2.5.17"></script>
<div id="app">
  <!-- 1000円以上になるまで、赤く表示する -->
  <div :style="errorMessageStyle">
    <p>{{ items[0].name }}: {{ items[0].price }} x {{ items[0].quantity }}</p>
    <p>小計: {{ totalPrice | numberWithDelimiter }}円</p>
    <p>合計(税込): {{ totalPriceWithTax | numberWithDelimiter }}円</p>
    <p v-show="!canBuy">
      {{ 1000 | numberWithDelimiter }}円以上からご購入いただけます
    </p>
  </div>
</div>
```

- 算出プロパティの追加部分。

```js
    errorMessageStyle: function () {
      // canBuyが偽の時に赤く表示する
      return {
        border: this.canBuy ? '' : '1px solid red',
        color: this.canBuy ? '' : 'red'
      }
    }
  }
```

- 1000円に満たない時

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/0a34504a-0bcb-3265-e90e-10b79a249a93.png)

- コンソールで個数を100個に変更

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/b43e2420-b3d1-a0d0-0db5-f99f8d50e2d2.png)

## リストレンダリング（v-for）

- v-forディレクティブで、配列あるいはオブジェクトのデータをリストレンダリングできる。
- `v-for="要素 in 配列"`のように書く。
- v-bind:key="・・・"で、生成時に一意なキーを各要素に与える必要がある。

```html
<!-- data: { arr: [ 'い', 'ろ', 'は']} -->
<ul>
  <li v-for="item in arr" v-bind.key="item">{{ item }}</li>
</ul>

インデックスあり
<ul>
  <li v-for="(item,index) in arr" v-bind.key="item">{{ index }}{{ item }}</li>
</ul>
```

### サンプルアプリケーションでの実装

- 以下のように、v-forで、リスト表示する。

```html
    <ul>
      <!-- 各商品の単価と購入個数をリスト表示する -->
      <li v-for="item in items" v-bind:key="item.name">
      {{ item.name }}: {{ item.price }} x {{ item.quantity }} = {{ item.price * item.quantity | numberWithDelimiter }}円
      </li>
    </ul>
```

- 1000円に満たない時

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/cf94bf91-5598-f691-3921-b076af357dc7.png)

- コンソールで個数を100個に変更

![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/93cee3d3-77d6-2cbc-c94c-03fdc9a73532.png)

## イベントハンドリング（v-on）

- v-onディレクティブは、イベントが起きた時に属性値の式を実行する。
- `v-on:イベント名="式として実行したい属性値"`で定義する。

```html
    <li v-for="item in items" v-bind:key="item.name">
      <!-- v-onでイベントが発生した時に属性値で指定した式を評価する -->
      {{ item.name }}の個数: <input type="number" v-on:input="item.quantity = $event.target.value" v-bind:value="item.quantity" min="0">
    </li>
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/88686/1279205a-aeb2-4b3d-410f-bfb50b752c90.png)


- v-onは、@で置き換えることができる。

```html
<input type="number" @input="item.quantity = $event.target.value" :value="item.quantity" min="0">
```

## フォーム入力バインディング（v-model）

- v-on:input、v-bind:valueを記述するのは骨の折れる作業。
- v-modelディレクティブを使えば、双方データバインディングが実現できる。
- ビューで変更があった場合はデータを更新し、データが変更があった場合はビューを再レンダリングする。

```html
 <input type="number" v-model="item.quantity" min="0">
```

- `v-model.lazy`のように、修飾子を付けることにより動作を変えられる。(lazyはchangeイベントで、inputのフォーカスから外れた時)

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