3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

アイテム一覧へアイテムを追加したときにシンプルなアニメーションを適用する

Posted at

概要

アイテム一覧にアイテムを追加したときにフェードインのアニメーションを適用するデモアプリケーションです。
なおVue.jsのトランジション機能を利用したごく普通のアニメーションになります。

環境

  • Windows 10 Professional
  • Node.js 6.11.5
  • Vue.js 2.5.16
    • Vuetify
  • Visual Studio Code 1.23.0

参考

アイテム一覧

  • アイテムデータの持ち方とアイテムの追加処理はダミーです。

アイテム一覧を表示するコンポーネント

Cards.vue
<template>
  <div class="cards">
    <slot name="nav"></slot>
    <div id="e3" style="max-width: 500px; margin: 20px auto;" class="grey lighten-3">
      <v-card>
        <v-container fluid style="min-height: 0; text-align: left;" grid-list-lg>
          <transition-group name="card-anim">
            <v-layout row wrap v-for="(item, index) in items" v-bind:key="index">
              <component v-bind:is="cardType(item)" v-bind:item="item" />
            </v-layout>
          </transition-group>
        </v-container>
      </v-card>
      <div>
        <v-container fluid style="min-height: 0;">
          <v-layout row>
            <v-flex xs12>
              <v-btn color="success" v-on:click="addList">More</v-btn>
            </v-flex>
          </v-layout>
        </v-container>
      </div>
    </div>
    <slot name="footer"></slot>
  </div>
</template>

<script>
import NormalCard from '@/components/NormalCard'
import ImageCard from '@/components/ImageCard'

export default {
  name: 'Cards',
  components: {
    'normal-card': NormalCard,
    'image-card': ImageCard
  },
  data () {
    return {
      itemMaster: [],
      items: [],
      itemIndex: 0
    }
  },
  mounted () {
    this.itemMaster = [
      { title: 'ゼルダの伝説', description: '任天堂から発売されたゲームソフト。ゼルダの伝説シリーズの一作目にあたる。', color: 'green darken-4' },
      { title: 'リンクの冒険', description: '任天堂より昭和62年1月14日に発売されたファミリーコンピュータ ディスクシステム用アクションアドベンチャーゲーム。', color: 'light-green darken-4' },
      { title: 'ゼルダの伝説 神々のトライフォース', description: '平成3年11月21日に任天堂から発売されたスーパーファミコン用ゲームソフト。', color: 'green accent-4' },
      { title: 'ゼルダの伝説 夢をみる島', description: '任天堂から平成5年6月6日に発売されたゲームボーイ用アクションアドベンチャーゲーム。', color: 'orange darken-4' },
      { title: 'ゼルダの伝説 時のオカリナ', description: '平成9年11月21日に任天堂より発売されたNINTENDO64(N64)用アクションアドベンチャーゲーム、アクションRPG。', color: 'lime darken-4' },
      { title: 'ゼルダの伝説 ムジュラの仮面', description: '任天堂より平成12年4月27日に発売されたNINTENDO64用3DアクションRPG。', color: 'deep-purple darken-4' }
    ]
    this.items.push(this.itemMaster[0])
    this.items.push(this.itemMaster[1])
    this.itemIndex = this.items.length
  },
  methods: {
    addList () {
      if (this.itemMaster.length > this.itemIndex) {
        this.items.push(this.itemMaster[this.itemIndex++])
      }
    },
    cardType (item) {
      if (item.image) {
        return ImageCard
      } else {
        return NormalCard
      }
    }
  }
}
</script>

<style scoped>
.card-anim-enter-active {
  animation: fadeInUp .7s;
  animation-delay: .4s;
  opacity: 0;
}

@keyframes fadeInUp {
  0% {
    transform: translateY(60px);
    opacity: 0;
  }
  60% {
    opacity: .3;
  }
  100% {
    transform: translateY(0px);
    opacity: 1;
  }
}
</style>

アイテム1件分を表示するコンポーネント

NormalCard.vue
<template>
  <v-flex xs12>
    <v-card v-bind:color="item.color" class="white--text" v-bind:tile="false" v-bind:hover="true">
      <v-card-title primary-title>
        <div class="headline">{{ item.title }}</div>
        <div>{{ item.description }}</div>
      </v-card-title>
      <v-card-actions>
        <v-btn flat dark>Details</v-btn>
      </v-card-actions>
    </v-card>
  </v-flex>
</template>

<script>
export default {
  name: 'NormalCard',
  props: {
    'item': {
      type: Object,
      required: true
    }
  }
}
</script>

アニメーションのポイント

その1

繰り返し要素にアニメーションを適用するにはtransition-groupを使用します。

<transition-group name="card-anim">
  <v-layout row wrap v-for="(item, index) in items" v-bind:key="index">
    <component v-bind:is="cardType(item)" v-bind:item="item" />
  </v-layout>
</transition-group>

その2

Vue.jsのトランジションには決められた6つのCSSクラスがあります。クラス名にはtransition又はtransition-groupのname属性がprefixとして付きます。(name属性を省略するとv-になります。)

この記事の例では、transition-groupのname属性に"card-anim"を指定してるので、6つのクラス名は以下のようになります。

  • card-anim-enter
    • enterの開始状態
  • card-anim-enter-active
    • enterの活性状態
  • card-anim-enter-to
    • enterの終了状態
  • card-anim-leave
    • leaveの開始状態
  • card-anim-leave-active
    • leaveの活性状態
  • card-anim-leave-to
    • leaveの終了状態

それぞれの状態時に発生させるアニメーションをCSSで定義します。この例ではアイテム追加時に下(60pxずれた位置)から上へ縦方向にフェードインするアニメーションを適用しています。
translateYtranslateXに変えると横方向にフェードインするようになります。

.card-anim-enter-active {
  animation: fadeInUp .7s;
  animation-delay: .4s;
  opacity: 0;
}

@keyframes fadeInUp {
  0% {
    transform: translateY(60px);
    opacity: 0;
  }
  60% {
    opacity: .3;
  }
  100% {
    transform: translateY(0px);
    opacity: 1;
  }
}

アイテムを削除したときにフェードアウトのアニメーションを適用したい場合は、下記のように"leave-active"のanimationにreverseを付けてエフェクトを反転させます。

.card-anim-leave-active {
  animation: fadeInUp .7s reverse;
}

アニメーションの様子

アニメーションの様子をgifにしました。
最初に2件表示されている状態から、MOREボタンを押して1件ずつアイテムを追加している様子です。


xee2.gif


3
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?