Vue.jsのTransitionでいい感じのアプリにする

## 自己紹介

![icon_resize.png](https://qiita-image-store.s3.amazonaws.com/0/11510/b725215d-9a59-0e63-2111-64bc578c5f71.png)

* nasum
* github: https://github.com/nasum
* twitter: https://twitter.com/tomato360
* 主にRubyとかRailsで仕事しています
* 趣味でVue.jsを使っています

---

## 今日話すこと

* Transitionの話
* Transitionを使うとアプリがいい感じになる（個人調べ）話
    * 自分で作っているTwitterクライアントをベースに紹介
    * https://github.com/nasum/twish

---
## Transitionの基本

* 詳しくは公式ガイドを見るのが一番早い
* https://jp.vuejs.org/v2/guide/transitions.html
* 今日お話するのはCSS transition を使った例

---
## 簡単な例

動的に動かしたい要素をtransitionコンポーネントで囲む

```HTML
<transition name="fade">
  <p v-if="show">hello</p>
</transition>
```

`v-if` での要素の表示・非表示に連動してくれるようになる（`v-show` でもOK）

---

## Transition時に付与されるクラス

* 詳しくは（以下略
* https://jp.vuejs.org/v2/guide/transitions.html#トランジションクラス
* 要素が表示されるとき
    * `v-enter` → `v-enter-active` → `v-enter-to`
* 要素が非表示されるとき
    * `v-leave` → `v-leave-active` → `v-leave-to`

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


* それぞれのクラスにtransitionの設定を書いていく。

---

## Transitionのクラス名の接頭辞について

* transitionコンポーネントの `name` 属性に任意の文字を与えれば付与されるクラスの `v-` が置き換えられる

例

```HTML
<transition name="fade">
```

なら

`fade-enter` `fade-enter-active` `fade-enter-to`

---

## Transitionコンポーネントの何が嬉しいか

* 今まで自分の手でタイミングよく付与していたクラスの制御を `Vue` 側に任せられる。
* クラスの型が決まっているので自分たちはCSSのことだけ考えることができる。

---

## Transitionのまとめ

* transitionコンポーネントで囲む
* 自動的に付与されるクラスに設定を書く

これだけ！らくちん！

---

## ここからさき

* transitionの事例などを紹介

---
## モーダル

![twish_tweet.gif](https://qiita-image-store.s3.amazonaws.com/0/11510/785d70da-5a26-dde1-9590-8c6b540ddad3.gif)

---
## こんな感じの実装

https://github.com/nasum/twish/blob/master/src/renderer/components/TweetDialog.vue

```html

<transition name="fade" v-on:enter="enter">
  <div class="grass-pane" v-show="$store.state.TweetDialog.open" @click="clickGrassPane">
     ...modalのあれこれ
  </div>
</transition>
```

```js
methods: {
    clickGrassPane: function () {
      //クローズの処理。ストアのopenを変えている
      this.$store.dispatch('closeTweetDialog');
    },
}
```

```css
/* 実はガイドに書いてあるのがそのまま */
.dialog-enter-active, .dialog-leave-active {
  transition: opacity .5s
}
.dialog-enter, .dialog-leave-to {
  opacity: 0
}
```

`v-show` を検知してtransitionしてくれる。動きはcssに書くだけ。

---

## Tweetの制限

![twish_tweet_limit.gif](https://qiita-image-store.s3.amazonaws.com/0/11510/5139df66-55c6-a0a3-4a26-99ecbf831143.gif)

---

## こんな感じの実装

https://github.com/nasum/twish/blob/master/src/renderer/components/TweetDialog.vue

```html
<transition>
  <div v-bind:class="{ ok: textState, ng: !textState }">
    {{ count }}
    <transition mode="out-in">
      <span class="icon" v-bind:class="{ 'icon-check': textState, 'icon-cancel': !textState }" v-bind:key="textState"></span>
    </transition>
  </div>
</transition>
```

```js
computed: {
  textState: function (e) {
    if (this.count <= 150) {
      return true;
    } else {
      return false;
    }
  },
  count: function () {
    return this.$store.state.TweetDialog.message.length;
  }
},
```

---

## タイムライン

![twish_timeline.gif](https://qiita-image-store.s3.amazonaws.com/0/11510/3f908725-b5ea-ba0d-1255-b20a5454be26.gif)

---

## こんな感じの実装

https://github.com/nasum/twish/blob/master/src/renderer/components/HomeTimeline.vue

```html
<transition-group name="list" tag="div">
  <tweet :status="status" v-for="status in sliceTweets" :key="status.id" @click='showDetail(status)'></tweet>
</transition-group>
```

```js
computed: {
  sliceTweets: function(){
    return this.$store.state.Tweet.displayTweets.slice(0, this.displayCount);
  }
},
```

```css
.list-enter-active, .list-leave-active {
  transition: all 1s;
}
.list-enter, .list-leave-to {
  opacity: 0;
  transform: translateY(-30px);
}
```

---

## Fav（いいね）

![twish_tweet_fav.gif](https://qiita-image-store.s3.amazonaws.com/0/11510/301c4d70-f3cc-8b25-0c8b-84c42acdbe35.gif)

---

## こんな実装

https://github.com/nasum/twish/blob/master/src/renderer/components/Tweet.vue


```html
<transition name="fav" mode="out-in">
  <span class="icon icon-heart reaction" @click="like" @click.stop v-if='status.favorited' key='onFav'></span>
  <span class="icon icon-heart-empty reaction" @click="like" @click.stop v-if='!status.favorited' key='offFav'></span>
</transition>
```

```js
methods: {
  like: function () {
    if (this.status.favorited) {
      this.$store.dispatch('destroyLike', { status: this.status });
    } else {
      this.$store.dispatch('createLike', { status: this.status });
    }
  },
}
```

```css
.fav-enter-active, .fav-leave-active {
  transition: all .3s ease;
}
.fav-enter, .fav-leave-to {
  opacity: 0;
  transform: translateY(30px);
}
```


---

## まとめ

* transitionはCSSのことだけを考えればいいので楽
* アプリケーションがより魅力的になる！
* CSSアニメーションとかの難しさに直面しても負けないで！
    * 僕はちょっと怖気づいているｗ