Step by Step で始める Vue.js の CSSトランジション

Vue.js では、`CSSトランジション` を使ったアニメーションの実装が簡単にできます。
実装自体はシンプルなのですが、公式サイトが少しわかりにくいなぁと思ったので、Step by Step 形式で解説していきます。

[Enter/Leave とトランジション一覧 — Vue.js](https://jp.vuejs.org/v2/guide/transitions.html)

## 流れ

|Step  |目的|
|------|---|
|Step 0|アニメーションをしていない画面を用意|
|Step 1|`<transition>`でくくり`.v-enter`を追加する|
|Step 2|`.v-enter-active` `.v-enter-to` を追加してアニメーションにする|
|Step 3|`.v-enter-to` でこまかく制御する|
|Step 4|属性値の変更を追ってみる|
|Step 5|`.v-leave` を使った消えるタイミングのCSSトランジション|
|Step 6|トランジションに名前を付ける|


## Step 0 アニメーションをしていない画面を用意
まずアニメーションをしていない画面を用意します。
アプリケーション自体は、表示非表示を切り替えるボタンがあるだけのシンプルなものです。
表示・非表示が一瞬で変わっています。

<p data-height="265" data-theme-id="0" data-slug-hash="JejOQP" data-default-tab="html,result" data-user="howdy39" data-pen-title="Step by Step で始める Vue.js の CSSトランジション Step 0" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/JejOQP/">Step by Step で始める Vue.js の CSSトランジション Step 0</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## Step 1 `<transition>`でくくり`.v-enter`を追加する
CSSトランジションを行うには `transition`タグでアニメーションしたい要素をくくります。
今回は、`Hello, world!`の部分を対象要素とします。

```diff:pug
doctype html
script(src="https://unpkg.com/vue@2.5.7")
#app
  button(@click="isShown = !isShown") 表示の切り替え
  | {{isShown}}
+   transition()
-   p(v-show="isShown") Hello, world!!
+     p(v-show="isShown") Hello, world!!
```

`transform`を使って右から左に移動するようなアニメーションを作ります。
まずアニメーション開始時のスタイルを `v-enter` クラスで指定します。

```diff:SCSS
+ .v-enter {
+   transform: translateX(300px);
+ }
```

では実行結果を見てみましょう。
表示される瞬間、一瞬だけ右にちらっと表示されることが確認できます。
※出ないこともあります（描画タイミングのせいかな？）。なんどかやってみてください。

これは `v-enter` クラスが **一瞬だけ** 設定されるためです。
※設定の流れはあとで解説するので `v-enter` クラスが設定されているんだな。ということだけ確認できればOKです。


<p data-height="265" data-theme-id="0" data-slug-hash="vQYqwL" data-default-tab="css,result" data-user="howdy39" data-pen-title="Step by Step で始める Vue.js の CSSトランジション Step 1" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/vQYqwL/">Step by Step で始める Vue.js の CSSトランジション Step 1</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## Step 2 `.v-enter-active` を追加してアニメーションにする
一瞬だけ出てもしょうがないので、左にスルーっと動くアニメーションを設定します。
`v-enter-active` クラスで`transition`を指定します。

CSSの意味がよくわからないという方は、次の記事がとてもわかり易いのでこの機会にぜひ覚えましょう。
[【CSS3】Transition（変化）関連のまとめ - Qiita](https://qiita.com/7968/items/812d6a21fc4dd9ae9c75#no05-transition%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3)


```diff:SCSS
+ .v-enter-active {
+  transition: transform 1000ms ease;
+ }
```

では実行結果を見てみましょう。
左にスルーっと動くアニメーションになっていることが確認できます。


<p data-height="265" data-theme-id="0" data-slug-hash="LXYweN" data-default-tab="css,result" data-user="howdy39" data-pen-title="Step by Step で始める Vue.js の CSSトランジション Step 2" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/LXYweN/">Step by Step で始める Vue.js の CSSトランジション Step 2</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## Step 3 `.v-enter-to` でこまかく制御する
`v-enter-to`クラスを指定することでアニメーションの最後の状態を指定できます。
同じ`transform`を使っても面白くないので`opacity`を使って不透明度を変えてみましょう。


```diff:SCSS
.v-enter {
  transform: translateX(300px);
+   opacity: 0;
}

.v-enter-active {
-   transition: transform 1000ms ease;
+   transition: all 1000ms ease;
}

+ .v-enter-to {
+   opacity: 0.7;
+ }
```

では実行結果を見てみましょう。
薄い状態から濃い状態になっているのが確認できます。
ポイントは最後の瞬間です、`opacity:0.7`から、デフォルトの`opacity:1`にガクッと変わります。
`v-enter-to`は最終的には取り除かれてしまうため、このような動きになるのです。


<p data-height="265" data-theme-id="0" data-slug-hash="dQyxeO" data-default-tab="css,result" data-user="howdy39" data-pen-title="Step by Step で始める Vue.js の CSSトランジション Step 3" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/dQyxeO/">Step by Step で始める Vue.js の CSSトランジション Step 3</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## Step 4 属性値の変更を追ってみる
実際に属性値の変更をデバッグで止めてスタイルとクラスの変更を追ってみると、理解がはかどりるので追ってみましょう。

###v-enterが追加される

```diff:v-enterが追加される
- <p style="display: none;">Hello, world!!</p>
+ <p style="display: none;" class="v-enter">Hello, world!!</p>
```

### v-enter-activeが追加される

```diff:v-enter-activeが追加される
- <p style="display: none;" class="v-enter">Hello, world!!</p>
+ <p style="display: none;" class="v-enter v-enter-active">Hello, world!!</p>
```

### display_noneが取り除かれる

```diff:display_noneが取り除かれる
- <p style="display: none;" class="v-enter">Hello, world!!</p>
+ <p style="" class="v-enter v-enter-active">Hello, world!!</p>
```

### v-enter-toが追加される

```diff:v-enter-toが追加される
- <p style="" class="v-enter v-enter-active">Hello, world!!</p>
+ <p style="" class="v-enter v-enter-active v-enter-to">Hello, world!!</p>
```

### v-enterが取り除かれる

```diff:v-enterが取り除かれる
- <p style="" class="v-enter v-enter-active v-enter-to">Hello, world!!</p>
+ <p style="" class="v-enter-active v-enter-to">Hello, world!!</p>
```

### v-enter-toが取り除かれる
```diff:v-enter-toが取り除かれる
- <p style="" class="v-enter-active v-enter-to">Hello, world!!</p>
+ <p style="" class="v-enter-active">Hello, world!!</p>
```

### v-enter-activeが取り除かれる
```diff:v-enter-activeが取り除かれる
- <p style="" class="v-enter-active">Hello, world!!</p>
+ <p style="">Hello, world!!</p>
```

### ポイント
`<transition>`を追加しても最終的には`style="display: none;"`が`style=""` になっているだけです。

つまり、`<transition>` で囲っておけば、CSSトランジションに利用できるクラスの追加や削除を裏で行ってくれます。
Vue.jsを利用する側は、そのクラスの中身を設定しておくだけで簡単にCSSトランジションをつかったアニメーションが実装できるということですね。


## Step 5 `.v-leave` を使った消えるタイミングのCSSトランジション
今まで見ていたのは、表示されるタイミング（`Enter`）でした。
表示が消えるタイミング（`Leave`）でも同じようなことが行えます。

クラス名の `v-enter` が `v-leave` になるだけです。
表示されるときが右から左に移動するアニメーションだったので、左に移動するアニメーションを設定してみましょう。

```diff:SCSS
.v-enter {
  transform: translateX(300px);
  opacity: 0;
}

- .v-enter-active {
+ .v-enter-active,
+ .v-leave-active {
  transition: all 1000ms ease;
}

- .v-enter-to {
+ .v-enter-to,
+ .v-leave {
  opacity: 0.7;
}

+ .v-leave-to {
+   opacity: 0;
+   transform: translateX(-300px);
+ }
```

では実行結果を見てみましょう。
消えるときは左に移動するのが確認できます。

<p data-height="265" data-theme-id="0" data-slug-hash="gQbYMd" data-default-tab="css,result" data-user="howdy39" data-pen-title="Step by Step で始める Vue.js の CSSトランジション Step 5" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/gQbYMd/">Step by Step で始める Vue.js の CSSトランジション Step 5</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


## Step 6 トランジションに名前を付ける
デフォルトは`v-hoge`になりますが、これは変更できます。
必要に応じて名前をつけると良いでしょう。

```diff:pug
doctype html
script(src="https://unpkg.com/vue@2.5.7")
#app
  button(@click="isShown = !isShown") 表示の切り替え
  | {{isShown}}
-   transition()
+   transition(name="fade")
    p(v-show="isShown") Hello, world!!

```

```diff:SCSS
- .v-enter {
+ .fade-enter {
  transform: translateX(300px);
  opacity: 0;
}

- .v-enter-active,
- .v-leave-active {
+ .fade-enter-active,
+ .fade-leave-active {
  transition: all 1000ms ease;
}

- .v-enter-to,
- .v-leave {
+ .fade-enter-to,
+ .fade-leave {
  opacity: 0.7;
}

- .v-leave-to {
+ .fade-leave-to {
  opacity: 0;
  transform: translateX(-300px);
}
```


<p data-height="265" data-theme-id="0" data-slug-hash="YRPKQL" data-default-tab="html,result" data-user="howdy39" data-pen-title="Step by Step で始める Vue.js の CSSトランジション Step 6" class="codepen">See the Pen <a href="https://codepen.io/howdy39/pen/YRPKQL/">Step by Step で始める Vue.js の CSSトランジション Step 6</a> by Tatsuya Nakano (<a href="https://codepen.io/howdy39">@howdy39</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>



## 参考

[Enter/Leave とトランジション一覧 — Vue.js](https://jp.vuejs.org/v2/guide/transitions.html)


## あとがき
最近 Vue.js を業務で本格的に触り始めました。
初心者目線でわかりにくいなぁと思ったことを解決する記事をどんどん書いていきます。