Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vue.js wrong transition group animation position

at first I'm css beginner I was trying to make vue.js animation for some items and it worked well but I got wrong animation

-We have button to add element to the array randomly

-We can click at element to remove it

problem:

-The animation always run on the last item

I expected that vue js should apply animation on the item which added or removed

What is the wrong in code that make the animation go wrong ??

What should i change or add to make the animation work correctly ??

new Vue({
  el: "#app",
  data: {
    myNumbers: [1, 2, 3, 4],
    highestNumberInMyNumbers: 4
  },
  methods: {
    addNumber() {
      this.highestNumberInMyNumbers++;
      this.myNumbers.splice(Math.floor(Math.random() * this.myNumbers.length), 0, this.highestNumberInMyNumbers);
    },
    removeNumber(element) {
      this.myNumbers.splice(element, 1)
    }
  }
})
.mix-enter {
  opacity: 0;
}

.mix-enter-active {
  transition: opacity 500ms;
  animation: mixing-in 600ms ease-in forwards;
}

.mix-leave {}

.mix-leave-active {
  transition: opacity 1000ms;
  animation: mixing-out 0.4s ease-in forwards;
  opacity: 0;
}

@keyframes mixing-in {
  from {
    transform: translateX(-20px) translateY(20px);
  }
  to {
    transform: translateX(0px) translateY(0px);
  }
}

@keyframes mixing-out {
  from {
    transform: translateX(0px) translateY(0px);
  }
  to {
    transform: translateX(-20px) translateY(-20px);
  }
}
<script src="https://vuejs.org/js/vue.min.js"></script>
 <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>





<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div id="app">
  <h2>group transition for directive v-for </h2>
  <hr>
  <button @click="addNumber">Add number</button>
  <br>
  <br>
  <div class="row">
    <ul class="col-xs-4 col-sm-4 col-md-4 col-lg-4 col-xs-offset-4">
      <transition-group name="mix" mode="out-in">

        <li class="alert alert-success list-unstyled" style="height: 40px; padding: 10px 15px;margin-bottom: 8px;cursor: pointer;" v-for="(number,index) in myNumbers" @click="removeNumber(index)" :key="index">{{number}}
        </li>
      </transition-group>
    </ul>
  </div>
</div>
like image 593
Mustafa Agamey Avatar asked Apr 24 '17 21:04

Mustafa Agamey


2 Answers

There is a bug in transition-group!

When you bind the key of li as the index, every time you remove a li, the animation always happend at the last li element.

So, if you want to use the animation with li , you can bind the key with number in your case.

<transition-group name="mix"
                  mode="out-in">
    <li class="alert alert-success list-unstyled"
        style="height: 40px; padding: 10px 15px;margin-bottom: 8px;cursor: pointer;"
        v-for="(number,index) in myNumbers"
        @click="removeNumber(index)"
        :key="index">
        {{number}}
    </li>
</transition-group>

vs

<transition-group name="mix"
                  mode="out-in">
    <li class="alert alert-success list-unstyled"
        style="height: 40px; padding: 10px 15px;margin-bottom: 8px;cursor: pointer;"
        v-for="(number,index) in myNumbers"
        @click="removeNumber(index)"
        :key="number">
        {{number}}
    </li>
</transition-group>

Finally, if you use animation with transition-group , do not bind the key to index , instead of item or number (in your case).

No matter what , make sure the key has the unique value.

like image 158
percy507 Avatar answered Sep 25 '22 01:09

percy507


Solution

Don't use index anywhere in the v-bind:key when using transition or transition-group.

Explanation

There is a bug/missing documentation, as well as bad documentation in the cookbook on vuejs.org, but there's a detailed explanation in the comments [1] on how indexes work, but no recognition this is a problem for developers in it's current state.

I have posted a few times to github, but the Vue.js developers there seem dismissive at best and refuse to either document this behavior or recognize this as a problem.

Reproduction of bug/error

There are three examples in the codepen below. The #1 works, the #2 uses :key="index" (your specific error above) and #3 uses :key="item +'_'+ index".

#2 and #3 give the error you are experiencing.

https://codepen.io/megacromulent/pen/wEzWNL

Summary of codepen:

This one works: (using item as :key)

<transition-group name="fade" tag="ol">
  <li v-for="(item, index) in items"
      v-bind:key="item">
    {{item}}
  </li>
</transition-group>

This one fails: (using index as :key)

<transition-group name="fade" tag="ol">
  <li v-for="(item, index) in items"
      v-bind:key="index" >
    {{item}}
  </li>
</transition-group>

This one fails worse: (concatenating index with string in :key)

<transition-group name="fade" tag="ol">
  <li v-for="(item, index) in items"
      v-bind:key="item + '_' + index" >
    {{item}}
  </li>
</transition-group>

Bug report (rejected)

I submitted this bug report to Vue.js devs here:

"Transition-group animates only last element if using index as the key"

https://github.com/vuejs/vue/issues/8718

It got closed instantly, so based on their input (requested I do a PR for comment, but that is not in my wheelhouse) I followed up with this feature request for the dev build to give an error, which would solve the problem at it's root.

Feature request (follow up, also rejected)

"Dev build console error when using index in :key value with v-for and transitions"

https://github.com/vuejs/vue/issues/8730

It seems reasonable to put a dev error on this issue, but the vue.js developers seem to think we should be able to figure this out on our own. I hope they come around and see this as a real issue. It's cost me hours of testing and reporting time to figure out.

I hope this helps other devs wasting time with this issue.

References

[1] https://github.com/vuejs/vue/issues/8718#issuecomment-416909724

like image 30
Megacromulent Avatar answered Sep 23 '22 01:09

Megacromulent