dominikj111
dominikj111

Reputation: 375

Why Vue animate differently in case replacing or creating and removing an array item?

I encounter with transition issue when animation when clicked on 'stream' button is different from animation after click on 'stream random' button from jsfiddle bellow.

Maybe I'm wrong with styling but could not realize why still getting the stream behaviour.

I need behaviour as on 'stream random' for array of div's.

Thank you

new Vue({
  el: '#list-complete-demo',
  data: {
    items: [1,2,3,4,5,6,7,8,9],
    nextNum: 10
  },
  methods: {
    add: function (item) {
      this.items.splice(this.items.length, 0, item)
    },
    remove: function () {
      return this.items.splice(0, 1)[0]
    },
    stream: function () {
    	this.add(this.remove())
    },
    streamrnd: function () {
    	this.add(this.nextNum++)
      this.remove()
    }
  }
})
.list-complete-item {
  transition: all 1s;
  display: inline-block;
  margin-right: 10px;
  border: 1px solid green;
  padding: 10px 10px 10px 10px;
}
.innerDiv {
  border: 1px solid red;
}
.list-complete-enter {
  opacity: 0;
  transform: translateX(40px);
}
.list-complete-leave-to {
  opacity: 0;
  transform: translateX(-40px);
}
.list-complete-leave-active {
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.js"></script>

<div id="list-complete-demo">

  <button v-on:click="stream">Stream</button>
  <button v-on:click="streamrnd">Stream Random</button>
  
  <transition-group 
    name="list-complete" 
    tag="div" 
    style="margin-top: 50px">
      <div
        v-for="item in items"
        :key="item"
        class="list-complete-item">
          <div class='innerDiv'>{{ item }}</div>
      </div>
  </transition-group>
</div>

Upvotes: 1

Views: 588

Answers (2)

Decade Moon
Decade Moon

Reputation: 34286

You have keyed the transition elements by the item itself, which is a number.

When you click the stream button, you're removing the last item from the array and inserting it at the beginning of the array. Since the key is the same for that item, Vue has detected that the item was moved in the array and transitions it as such.

When you click the stream random button, you are removing the last item from the array and inserting a new unique item with a different key than the existing items in the DOM. Vue will perform a leave transition for the removed item and an enter transition for the new item.

You need to use key to control how Vue reuses DOM elements for your items.

You can associate a unique numerical key for each item in your array to prevent Vue from reusing the spans:

<span v-for="item in items" :key="item.key">{{ item.value }}</span>
data: {
  items: [
    { key: 1, value: 1 },
    { key: 2, value: 2 },
    { key: 3, value: 3 },
    { key: 4, value: 4 },
    { key: 5, value: 5 },
    { key: 6, value: 6 },
    { key: 7, value: 7 },
    { key: 8, value: 8 },
    { key: 9, value: 9 },
  ],
  nextNum: 10,
  nextKey: 10
},

methods: {
  add(item) {
    this.items.splice(0, 0, {
      key: this.nextKey++,
      value: isNaN(item) ? this.nextNum++ : item,
    })
  },

  remove() {
    return this.items.splice(this.items.length - 1, 1)[0].value
  },

  stream() {
    this.add(this.remove())
  },

  streamrnd() {
    this.add(this.nextNum++)
    this.remove()
  }
}

Obviously you can simplify that code, but you get the idea.

Updated fiddle.

Upvotes: 1

Jeff
Jeff

Reputation: 25221

In the stream function, you are adding the element that was removed back into the array. So the animation moves it from the end to the start.

In the streamrnd function you are just removing it entirely, and adding a new one. So it animates accordingly.

Upvotes: 1

Related Questions