Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reset CSS animations in Vue

Tags:

css

vue.js

I have a list like this:

var v = new Vue({
  'el' : '#app',
  'data' : {
    'list' : [1,2,3,4,5,6,7,8,9,10]
  },
  
  methods: {
    activateClass($event){
      $event.target.classList.remove('animate');
      void $event.target.offsetWidth;
      $event.target.classList.add('animate');
    },
    changeRandomValue(){
      var randomAmount = Math.round(Math.random() * 12);
      var randomIndex = Math.floor(Math.random() * this.list.length);
      Vue.set(this.list, randomIndex, randomAmount)
    }
  },
  
  mounted(){
    var vm = this;
    setInterval(function(){
      vm.changeRandomValue();
    }, 500);
  }
})
.animate{
  animation: fade 0.5s;
}

@keyframes fade{
  0% { background:blue; }
  100% { background:white; }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
  <ul>
    <li v-for="item in list" v-html="item" @click="activateClass($event)"></li>
  </ul>
</div>

If you run the above snippet, you'll see that if you click an li it will use this code:

activateClass($event){
  $event.target.classList.remove('animate');
  void $event.target.offsetWidth;
  $event.target.classList.add('animate');
}

To add a class to it once and play an animation (https://css-tricks.com/restart-css-animation/). Awesome!

Now, I also have a changeRandomValue() function that selects one element from the list array and change its value.

How would I use the activateClass method from inside of the changeRandomValue method?

I've had a few thoughts about using events on the element, so it would be something like:

<li v-for="item in list" v-html="item"
    @click="activateClass($event)"
    @myValueChanged="activateClass($event)"
></li>

But I don't think anything like that exists. I have also been looking into watchers but I don't think this is really what they are for.

I have no problem taking the element that has been clicked and finding the data that it is referencing, but I can't work out how to take the data that has been changed and then find its dom reference.

The reason I'm not using class bindings is that I need to trigger a reflow. Maybe there is a really easy way to do that with vue, but I'm not aware of it.

like image 729
Djave Avatar asked Dec 04 '17 12:12

Djave


People also ask

How do you reset an animation in CSS?

The key to restarting a CSS animation is to set the animation-name of an animation to 'none' and then setting it back to the original animation. As you can see this requires two steps. One to switch it to a different animation and one to set it back.

How do you repeat an animation in CSS?

The animation-iteration-count property in CSS is used to specify the number of times the animation will be repeated. It can specify as infinite to repeat the animation indefinitely.

What is animation fill mode in CSS?

The animation-fill-mode property specifies a style for the element when the animation is not playing (before it starts, after it ends, or both). CSS animations do not affect the element before the first keyframe is played or after the last keyframe is played. The animation-fill-mode property can override this behavior.


1 Answers

One easy solution would be to use class bindings and the animationend event.
You can also trigger the same solution programmatically, as shown in the mounted event.

new Vue({
  el: '#app',
  data: {
    items: [{
      id: 1,
      highlight: false
    }, {
      id: 2,
      highlight: false
    }]
  },
  mounted() {
    // Demonstrate programmatic highlighting
    setTimeout(() => {
      this.items[1].highlight = true
      setTimeout(() => {
        this.items[1].highlight = true
      }, 1000)
    }, 1000)
  },
  methods: {
    addClass(item) {
      item.highlight = true
    },
    removeClass(item) {
      item.highlight = false
    }
  }
})
p {
  cursor: pointer;
}

.animate {
  animation: fade 0.5s;
}

@keyframes fade {
  0% {
    background: blue;
  }
  100% {
    background: white;
  }
}
<script src="https://unpkg.com/vue"></script>

<div id="app">
  <p v-for="item in items" v-bind:class="{ animate: item.highlight }" v-on:click="addClass(item)" v-on:animationend="removeClass(item)">{{ item.id }}</p>
</div>
like image 124
Etheryte Avatar answered Nov 15 '22 08:11

Etheryte