I would like to toggle an 'active' class in a list of elements:
<div ref="gallery" class="slider">
<div class="slide active">
<div class="slide">
<div class="slide">
</div>
Using Vue and Vanilla JS
Slider() {
const slider = document.querySelectorAll('.slider')
for (const slide of slider) {
setInterval(function () {
const current = slide.querySelector('.active')
current.classList.remove('active')
const next = current.nextElementSibling || slide.firstElementChild
next.classList.add('active')
}, 5000)
}
}
While the above code does work, I feel it is not as clean as it could be.
Also, and mainly, if I target the slider using a Vue ref like:
const slider = this.$refs.gallery
it stops working
tony19 answer led me to reduce the code even further using Nuxt:
export default {
data() {
return {
activeIndex: 0,
slides: [
{ id: 1, text: 'Slide 1' },
{ id: 2, text: 'Slide 2' },
{ id: 3, text: 'Slide 3' },
]
}
},
mounted() {
this.Slider()
},
methods: {
Slider() {
setInterval(() => {
this.activeIndex = (this.activeIndex + 1) % this.slides.length
}, 3000)
}
}
}
<template>
<div class="slider">
<div v-for="(slide, index) in slides"
:key="slide.id"
:class="['slide', { active: index === activeIndex }]">
{{ slide.text }}
</div>
</div>
</template>
You can use a class binding that sets class to active based on the active index:
Declare an activeIndex property to hold the active index.
In the mounted hook, use setInterval() with a callback that increments activeIndex. Track the timer ID from setInterval() so that we can stop the timer later.
In the unmounted hook, stop the interval timer with clearInterval() on the timer ID.
Use the object syntax for class bindings to bind an active class only when the activeIndex matches the slide's index from v-for.
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
let timerId = -1
1️⃣
const activeIndex = ref(0)
const slides = ref([
{ id: 1, text: 'Slide 1' },
{ id: 2, text: 'Slide 2' },
{ id: 3, text: 'Slide 3' },
])
2️⃣
onMounted(() => {
timerId = setInterval(() => {
activeIndex.value = (activeIndex.value + 1) % slides.value.length
}, 3000)
})
3️⃣
onUnmounted(() => {
clearInterval(timerId)
})
</script>
<template>
<div ref="gallery" class="slider">
<div v-for="(slide, index) in slides"
:key="slide.id"
class="slide"
4️⃣
:class="{ active: index === activeIndex }">
{{ slide.text }}
</div>
</div>
</template>
I made this demo in vue.js format as per your request. Please have a look and see if this is what you actually want to achieve.
Demo :
new Vue({
el: '#app',
data: {
slideData: [{
name: 'Slide 1',
isActive: true
}, {
name: 'Slide 2',
isActive: false
}, {
name: 'Slide 3',
isActive: false
}]
},
mounted() {
this.slideData.forEach((obj) => {
setInterval(() => {
obj.isActive = !obj.isActive;
}, 3000);
});
}
})
.active {
color: white;
background-color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(slider, index) in slideData" class="slide" :class="{ active: slider.isActive }">
{{ slider.name}}
</div>
</div>