I wanted to make a component which gets text-box when mouse is over the image.
Below is HTML template.
<section class="item-container" v-for="(item, index) in items">
<div class="image-box" @mouseenter="changeStatus(index)">
<img class="image" src="item.link" alt>
</div>
<div class="text-box" @mouseleave="changeStatus(index)" v-if="show[index]">
<h4>{{ item.name }}</h4>
<p>{{ item.content }}</p>
</div>
</section>
And below is app.js
new Vue({
el: '#app',
data: {
show: [false, false, false],
items: [
{
name: 'Author 1',
content: 'Content 1'
},
{
name: 'Author 2',
content: 'Content 2'
},
{
name: 'Author 3',
content: 'Content 3'
}
]
},
methods: {
changeStatus: function(index) {
this.show[index] = !this.show[index];
console.log(this.show);
console.log(this.show[index]); // console gets it as expected
}
}
});
When I execute above codes, I can find that the show property has changed. However, v-if is not updated. Can't we use array[index] for v-if or is there other reason for it?
You can use a JS object instead of an array and get the same effect. In other words, replace show: [false, false, false],
with show: {0:false, 1:false, 2:false},
.
The problem is not about v-if
, it's because Vue cannot detect the changes of an array element directly, this is one of the limitation of JavaScript.
Thus, Vue provides some helper functions for this, like Vue.set
Change this this.show[index] = !this.show[index]
to Vue.set(this.show, index, !this.show[index])
then it should work.
Vue.set
is not the only solution, there are several ways to accomplish this, in case you may want to know.
You can use native methods of JavaScript array, Vue will hook on these methods so it can detect the changes.
Here is the example of the usage of .splice
this.show.splice(index, 1, !this.show[index])
Another way is to replace the array entirely. If you are using ES6, you can use the spread operator to clone the array easily:
this.show[index] = !this.show[index]
this.show = [...this.show]
.map
will also work because it returns a new array
this.show = this.show.map((el, i) =>
i === index ? !el : el
)
In component in methods you can use:
this.$set(this.show, index, !this.show[index])
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