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.
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.
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.
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.
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.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With