VueJS - Transition-group idea for single-item replacements

35 Views Asked by At

I see that it's impossible to add an "in-out" mode on "transition-group" (https://v2.vuejs.org/v2/guide/transitions#List-Transitions). Would you have any ideas or a solution for having an animation similar to "in-out" in the case of an item replacement?

I've reproduced the case I'd like to animate exactly, just click on "REPLACE BY NEW".

The problem is that when you replace an item, the animation isn't very good: you see two items playing the animation at the same time.

Animation when adding (good): enter image description here

Animation when removing (good): enter image description here

Animation when replacing (NOT good): enter image description here

Thanks.

let id = 0;

new Vue({
  data() {
    return {
      squares: [],
    };
  },
  mounted() {
     this.squares = _.times(4, this.createNewSquare);
  },
  methods: {
     createNewSquare() {
         id++;
         return {
             id: id,
             name: _.uniqueId('random_name_'),
         };
     },
     addSquare() {
         this.squares.push(this.createNewSquare());
     },
     removeSquare(id) {
             this.squares.splice(
           _.findIndex(this.squares, {id}),
             1
         );
     },
     replaceSquare(id) {
          const indexOldSquare = _.findIndex(this.squares, {id});
        const newSquare = this.createNewSquare();
        this.squares.splice(indexOldSquare, 1, newSquare);
     },
  },
}).$mount('#app')
.squares {
  display: flex;
}

.square {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 200px;
  height: 200px;
  background-color: #dc3545;
  margin: 10px;
  position: relative;
  color: #fff;
}

.replace,
.remove {
  background-color: #fff;
  color: #000;
  position: absolute;
  top: 10px;
  cursor: pointer;
  padding: 2px;
}

.replace:hover,
.remove:hover {
  background-color: #000;
  color: #fff;
}

.replace {
  left: 10px;
}
.remove {
  right: 10px;
}

@keyframes popupAnimation {
  from {
    transform: scale(0.9);
    opacity: 0;
  }

  to {
    transform: scale(1);
    opacity: 1;
  }
}

@keyframes popoutAnimation {
  from {
    transform: scale(1);
    opacity: 1;
  }

  to {
    transform: scale(0.9);
    opacity: 0;
  }
}

.list-enter-active,
.list-leave-active {
  animation: popupAnimation 1.5s;
}

.list-enter-from,
.list-leave-to {
  animation: popoutAnimation 1.5s;
}
        
.commands {
  margin-top: 50px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.16/vue.js"></script>

<div id="app">
  <transition-group name="list" tag="div" class="squares">
    <div v-for="square in squares" :key="square.id" class="square">
      <div class="infos">
        <div>
          id : {{ square.id }}
        </div>
        <div>
          name : {{ square.name }}
        </div>
      </div>
      
      <div class="replace" @click="replaceSquare(square.id)">
        REPLACE BY NEW
      </div>
      <div class="remove" @click="removeSquare(square.id)">
        X
      </div>
    </div>
  </transition-group>
  <div class="commands">
      <button @click="addSquare">
        Add
      </button>
  </div>
</div>

0

There are 0 best solutions below