Reputation: 407
I'm looking to loop through an array of span tags and add is-active
to the next one in line, every 3 seconds. I have it working but after the first one, it adds all the rest. How do I just pull that class from the active one and add it to the next array item?
I've read through the official documentation several times and there doesn't seem to be any mention of iterating individual items, just listing them all or pushing an item onto the list.
I'm not sure if 'index' comes in to play here, and how to grab the index of the span element to add/subtract is-active
. what am I doing wrong?
var firstComponent = Vue.component('spans-show', {
template: `
<h1>
<span class="unset">Make</span>
<br>
<span class="unset">Something</span>
<br>
<span v-for="(span, index) of spans" :class="{ 'is-active': span.isActive, 'red': span.isRed, 'first': span.isFirst }" :key="index">{{ index }}: {{ span.name }}</span>
</h1>
`,
data() {
return {
spans: [
{
name: 'Magical.',
isActive: true,
isRed: true,
isFirst: true
},
{
name: 'Inspiring.',
isActive: false,
isRed: true,
isFirst: true
},
{
name: 'Awesome.',
isActive: false,
isRed: true,
isFirst: true
}
]
};
},
methods: {
showMe: function() {
setInterval(() => {
// forEach
this.spans.forEach(el => {
if (el.isActive) {
el.isActive = false;
} else {
el.isActive = true;
}
});
}, 3000);
}
},
created() {
window.addEventListener('load', this.showMe);
},
destroyed() {
window.removeEventListener('load', this.showMe);
}
});
var secondComponent = Vue.component('span-show', {
template: `
<span v-show="isActive"><slot></slot></span>
`,
props: {
name: {
required: true
}
},
data() {
return {
isActive: false
};
}
});
new Vue({
el: "#app",
components: {
"first-component": firstComponent,
"second-component": secondComponent
}
});
.container {
position: relative;
overflow: hidden;
width: 100%;
}
.wrapper {
position: relative;
margin: 0 auto;
width: 100%;
padding: 0 40px;
}
h1 {
font-size: 48px;
line-height: 105%;
color: #4c2c72;
letter-spacing: 0.06em;
text-transform: uppercase;
font-family: archia-semibold, serif;
font-weight: 400;
margin: 0;
height: 230px;
}
span {
position: absolute;
clip: rect(0, 0, 300px, 0);
}
span.unset {
clip: unset;
}
span.red {
color: #e43f6f;
}
span.is-active {
clip: rect(0, 900px, 300px, -300px);
}
<div id="app">
<div class="container">
<div class="wrapper">
<spans-show>
<span-show></span-show>
</spans-show>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
Upvotes: 0
Views: 970
Reputation: 4732
To achieve desired result, I'd suggest to change the approach a bit.
Instead of changing value of isActive
for individual items, we can create a variable (e.g. activeSpan
, that will be responsible for current active span and increment it over time.
setInterval(() => {
// Increment next active span, or reset if it is the one
if (this.activeSpan === this.spans.length - 1) {
this.activeSpan = 0
} else {
this.activeSpan++
}
}, 3000);
In component's template, we make class is-active
conditional and dependent on activeSpan
variable:
:class="{ 'is-active': index === activeSpan, 'red': span.isRed, 'first': span.isFirst }"
If you still need to update values inside spans
array, it can be done in more simple way, via map
for example. Also included such case as optional in solution below.
Working example: JSFiddle
Sidenote: there is no need to add window listeners for load
event, as application itself is loaded after DOM is ready. Instead, method can be invoked inside created
hook. It is included in solution above.
Upvotes: 1