Vue.js の条件付きレンダリングを勉強する

# 条件付きレンダリング

## v-if
**v-if**ディレクティブは、要素を条件に応じて描画したい場合に使用する。

```html:html部分
<div id="example">
  <p v-if="awesome"> 条件がtrueの時に表示される </p>
</div>
```

```javascript:javascript部分
let app = new Vue({
  el: '#example',
  data: {
    awesome: false
  }
})
```

```javascript:開発者モードのConsole
app.awesome = true
// true
```

```:ブラウザの表示
条件がtrueの時に表示される
```

### v-else
通常のjavascript同様に**v-else**でelseを記述することが可能です。
**v-else**要素は、**v-if**または**v-else-if**要素の直後になければいけません。
それ以外の場合は認識されません。

```html:html部分
<div id="example">
  <p v-if="awesome"> 条件がtrueの時に表示される </p>
  <p v-else="awesome"> 条件がfalseの時に表示される </p>
</div>
```

```javascript:javascript部分
let app = new Vue({
  el: '#example',
  data: {
    awesome: false
  }
})
```

```javascript:開発者モードのConsole
app.awesome = true
// true
```

```:ブラウザの表示
条件がtrueの時に表示される
```

### v-else-if
通常のjavascript同様に**v-else-if**でelse ifを記述することが可能です。
**v-else-if**要素は、**v-if**または**v-else-if**要素の直後になければいけません。
それ以外の場合は認識されません。

```html:html部分
<div id="example">
  <p v-if="awesome == 'A'"> 条件がAの時に表示される </p>
  <p v-else-if="awesome == 'B'"> 条件がBの時に表示される </p>
  <p v-else-if="awesome == 'C'"> 条件がCの時に表示される </p>
  <p v-else="awesome"> 条件に当てはまらなった時に表示される </p>
</div>
```

```javascript:javascript部分
let app = new Vue({
  el: '#example',
  data: {
    awesome: ''
  }
})
```

```:ブラウザの表示
条件に当てはまらなった時に表示される
```

```javascript:開発者モードのConsole
app.awesome = 'A'
// "A"
// ブラウザの表示：条件がAの時に表示される

app.awesome = 'B'
// "B"
// ブラウザの表示：条件がBの時に表示される

app.awesome = 'C'
// "C"
// ブラウザの表示：条件がCの時に表示される

app.awesome = 'D'
// "D"
// ブラウザの表示：条件に当てはまらなった時に表示される
```

## テンプレートでのv-ifによる条件グループ
v-ifはディレクティブなので、１つの要素に付加する必要があります。
1要素よりも多くの要素を切り替えたい場合にHTML の[コンテンツテンプレート(< template >)](https://developer.mozilla.org/ja/docs/Web/HTML/Element/template)要素を使用します。  

```html:html部分
<div id="example">
  <template v-if="boxflg">
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
  </template>
</div>
```

```javascript:javascript部分
let app = new Vue({
  el: '#example',
  data: {
    boxflg: false
  }
})
```

```javascript:開発者モードのConsole
app.boxflg = true
// true
```

```:ブラウザの表示
Title
Paragraph 1
Paragraph 2
```

```html:開発者モードのElement
<div id="example">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</div>
```

htmlのElementにコンテンツテンプレートが含まれることはありません。

## key による再利用可能な要素の制御
Vue.jsは要素を可能な限り効率的に描画しようとしますが、１からレンダリングするかわりにそれら要素を再利用することがよくあります。  
Vue.jsを非常に速くするのに役立つ以外にも、これにはいくつかの便利な利点があります。  
たとえば、ユーザーが複数のログインタイプを切り替えることを許可する場合は、次のようにします。

+ UserNameでログイン
+ Emailでログイン

上記の２つを切り替える入力画面を作ります。

```html:html部分
<div id="example">
  <template v-if="loginType === 'username'">
    <label>Username</label>
    <input placeholder="Enter your username">
  </template>
  <template v-else>
    <label>Email</label>
    <input placeholder="Enter your email address">
  </template>
  <button @click="change">ログイン方法変更</button>
</div>
```

正直愚直なコードな気がして最善な書き方では無い気がしますが…

```javascript:javascript部分
let app = new Vue({
  el: '#example',
  data: {
    loginType: 'username'
  },
  methods: {
    change(){
      if (!(this.loginType == "username")) {
        this.loginType = "username"
      }else{
        this.loginType = "email"
      }
    }
  }
})
```

上記のコードでloginTypeを切り替えても、ユーザーが既に入力したものは消去されません。
両方のテンプレートが同じ要素を使用するので、< input > は置き換えられません。
placeholderが切り替わるだけです。
この結果は望ましい結果では無いかもしれません。
この2つの要素は完全に別個のもので、再利用したく無い場合があり、要素に一意であることを示すために**key**属性を追加します。

```html:html部分
<div id="example">
  <template v-if="loginType === 'username'">
    <label>Username</label>
    <input placeholder="Enter your username" key="username-input">
  </template>
  <template v-else>
    <label>Email</label>
    <input placeholder="Enter your email address" key="email-input">
  </template>
  <button @click="change">ログイン方法変更</button>
</div>
```
javascriptのコードは上記の例と変更はありません。
これでログイン方法が変更ボタンが押されるたびにinputが再利用されなくなります。

## v-show
条件的に要素を表示するための別のオプションです。  
使用方法は**v-if**とほとんど同じです。

```html:html部分
<div id="example">
  <p v-show="awesome"> 条件がtrueの時に表示される </p>
</div>
```

```javascript:javascript部分
let app = new Vue({
  el: '#example',
  data: {
    awesome: false
  }
})
```

```html:開発者モードのElements
<div id="example">
  <p style="display: none;"> 条件がtrueの時に表示される </p>
</div>
```

```javascript:開発者モードのConsole
app.awesome = true
// true
```

```:ブラウザの表示
条件がtrueの時に表示される
```

```html:開発者モードのElements
<div id="example">
  <p style> 条件がtrueの時に表示される </p>
</div>
```

**v-if**との違いは **v-sow**ディレクティブでは要素自体は常に描画されてDOMに維持するということです。
**v-show**はシンプルに要素の**display**CSSプロパティを切り替えているだけです。

### <font color="red">【注意】</font>
**v-show**はコンテンツテンプレートをサポートしていません。  

```html:アンチパターン
<div id="example">
  <template v-show="boxflg">
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
  </template>
</div>
```

これはコンテンツテンプレートがDOMのElementsに含まれないためです。

## v-if vs v-show
### v-if  
イベントリスナと子コンポーネント内部の条件ブロックが適切に破棄され、切り替えられると再レンダリングされるため、"リアル"な条件レンダリングです。

**v-if**は遅延描画(lazy)です。
初期表示においてfalseの場合レンダリングされず、条件がtrueになったときにレンダリングされます。

### v-show
要素は条件に関わらず常に描画されており、**display**CSSプロパティを切り替えているだけです。

### 結論
シンプルかつ頻繁に切り替える必要があるのならば**v-show**を使用し
複雑な処理、条件が実行時から変更されることがほとんどない場合は**v-if**を選ぶ


## あとがき
v-ifとv-forの題目はv-ifとv-forを同時に利用する事は推奨されておらずバッドプラクティスですということです。
詳細は[スタイルガイド](https://jp.vuejs.org/v2/style-guide/#v-for-%E3%81%A8%E4%B8%80%E7%B7%92%E3%81%AB-v-if-%E3%82%92%E4%BD%BF%E3%81%86%E3%81%AE%E3%82%92%E9%81%BF%E3%81%91%E3%82%8B-%E5%BF%85%E9%A0%88)を参照してください  

## 参考資料
[公式リファレンス](https://jp.vuejs.org/v2/guide/conditional.html)