search
LoginSignup
7

More than 3 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


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
What you can do with signing up
7