Search code examples
vue.jsanimejs

Animejs 3.2.1: Anime stagger not working with vue transition-group


I am trying to create a staggering animation effect in my project. I am working with vue 3 and animejs 3.2.1. Basically, I dynamically rendered a list like so:

<div class="products-container">
    <transition-group class="flex-container" tag="ul" appear @before-enter="beforeEnterCans" @enter="enterCans">
      <li class="dynamic-flex-children" v-for="cokeImage in cokeImages" :key="cokeImage.id">
        <img :src="cokeImage.src" :alt="cokeImage.title" class="can-image">
        <p>{{cokeImage.title}}</p>
      </li>
    </transition-group>
  </div>

This generates a list of eight items which I have in a layout in a grid using flex.

.products-container{
  height: 90vh;
  width: 100vw;
  overflow-y: hidden;
}
.flex-container{
  height: 100%;
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  padding: 5% 10%;
}
.dynamic-flex-children{
  list-style-type: none;
  flex-basis: 25%;
}
.dynamic-flex-children img{
  width: 40%;
}
.dynamic-flex-children p{
  font-size: 0.7rem;
}

As you can see, the <ul> have the vue animation hooks attached to the <transition-group>. In the component instance, I now used animejs to try to implement a staggering effect for each <li> when the list enters the screen

<script>
import anime from 'animejs/lib/anime.es.js';
export default {
  name: 'Products',
  data(){
    return {
      cokeImages: [
        { title: 'Cocacola Life', src: require('@/assets/cocacola-cans/cocacola-life.png'), id: 1 },
        { title: 'Cocacola Zero', src: require('@/assets/cocacola-cans/cocacola-zero.png'), id: 2 },
        { title: 'Diet Coke', src: require('@/assets/cocacola-cans/diet-coke.png'), id: 3 },
        { title: 'Cocacola Classic', src: require('@/assets/cocacola-cans/classic-coke-two.png'), id: 4 },
        { title: 'New Cocacola', src: require('@/assets/cocacola-cans/classic-cocacola.png'), id: 5 },
        { title: 'Vanilla', src: require('@/assets/cocacola-cans/cocacola-vanilla.png'), id: 6 },
        { title: 'Cocacola Light', src: require('@/assets/cocacola-cans/cocacola-light.png'), id: 7 },
        { title: 'Cocacola Cherry', src: require('@/assets/cocacola-cans/cocacola-cherry.png'), id: 8 }
      ]
    }
  },
  methods: {
    beforeEnterCans(el){
      el.style.transform = "translateX(-100%)"
      el.style.opacity = 0
    },
    enterCans(el){
      anime({
        targets: el,
        opacity: 1,
        translateX: 0,
        delay: anime.stagger(200, {start: 100}),
        easing: 'easeInOutSine'
      })
    }
  }

}
</script>

For whatever reason, the list deosn't stagger when they transition in.


Solution

  • After many trials and errors, I found the problem.

    enter(el){
          anime({
            targets: ".dynamic-flex-children",
            duration: 700,
            opacity: 1,
            translateX: 0,
            delay: anime.stagger(100, {start: 100, direction: "reverse"}),
            easing: 'easeInOutSine'
          })
        }
    

    anime.js uses classes to target elements. I was passing el to the targets options instead of the shared class name of all the dynamically generated <li> tags. I just changed the targets option from el to the shared class name .dynamic-flex-children and it worked.