VueJS transition on element in a loop?
Asked Answered
H

2

7

This is my code: I want to create a transition on the HelloWorld Component, everytime the data gets updated. The transition itself works fine

  <transition name="fade">
    <p v-if="awesome">Vue is awesome</p>
  </transition>

Here are my "cards" which are created dynamically.

  <v-row no-gutters>
    <v-col cols="12" sm="4" md="4" v-for="(todo, index) in todos" v-bind:key="index">
      <v-card class="pa-2" outlined tile>
        <transition name="fade">
          <HelloWorld
            v-bind:todos="todos"
            v-bind:index="index"
            v-bind:class="(todos[index].done)?'green':'red'"
          />
        </transition>
      </v-card>
    </v-col>
  </v-row>

Here the transition does not work.

CSS is here:

<style scoped>
.top {
  background: blue;
  color: white;
  display: flex;
  justify-content: space-around;
  border-bottom: 2.5px solid black;
}

.fade-enter {
  opacity: 0;
}

.fade-enter-active {
  transition: opacity 1s;
}

.fade-leave {
}

.fade-leave-active {
  transition: 1s;
  opacity: 0;
}
</style>

Why and how do it get it done to work?

Harville answered 8/12, 2019 at 14:47 Comment(0)
S
7

If you want to animate each element in a loop, you have to:

  • Put transition around the loop.
  • And also, use <transition-group>, not just <transition>
<v-row no-gutters>
  <transition-group name="fade-in" mode="out-in">
    <v-col cols="12" sm="4" md="4" v-for="(todo, index) in todos" v-bind:key="index">
      <v-card class="pa-2" outlined tile>
        <HelloWorld
          v-bind:todos="todos"
          v-bind:index="index"
          v-bind:class="(todos[index].done)?'green':'red'"
        />
      </v-card>
    </v-col>
  </transition-group>
</v-row>

And I would also advise you not to use 1s long animation, it's way too long. Do something like this:

CSS

.fade-in-enter-active {
  transition: all 0.5s ease;
}

.fade-in-leave-active {
  transition: all 0.5s ease;
}

.fade-in-enter, .fade-in-leave-to {
  position: absolute; /* add for smooth transition between elements */
  opacity: 0;
}

If the animation is twitchy, you can add position: absolute; in the enter and leave-to CSS rules (or only for leave-active).

Check out this page in vue docs: https://v2.vuejs.org/v2/guide/transitions.html#List-Move-Transitions

Sportswear answered 8/12, 2019 at 15:52 Comment(4)
thank you, transition works, but it cracks up the width of my cards totally :-/Harville
@DataMastery glad I could help. I updated the question (at the bottom) try it out.Sportswear
@DataMastery you can also try putting position: absolute; only inside the .fade-in-leave-active class instead of the other two, this might change the way it looks since it will only be absolute during the transition, you can see it demonstrated on the provided vue docs pageSportswear
Just a note for anyone else coming across this, I needed to change the "name" attribute to "fade-in" when using this example.Zestful
A
1
<v-row no-gutters>
  <transition-group name="fade" class="row">
    <v-col cols="12" sm="4" md="4" v-for="(todo, index) in todos" :key="todo.randomKey">
      <v-card class="pa-2" outlined tile>
        <HelloWorld
          v-bind:todos="todos"
          v-bind:index="index"
          v-bind:class="(todos[index].done)?'green':'red'"
        />
      </v-card>
    </v-col>
   </transition-group>
 </v-row>

you need to do multiple edits:

  1. use <transition-group> instead of <transition>.
  2. wrap <v-col> using <transitiono-group>.
  3. add class="row" to the <transition-group>.
  4. replace the index with a unique key inside todo objects for example todo.id or todo.randomKey. Using index as key is like not using a key at all.
Affricative answered 16/9, 2020 at 8:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.