web-dev-qa-db-fra.com

VueJS v-if = array [index] ne fonctionne pas

Je voulais créer un composant qui obtient une zone de texte lorsque la souris survole l'image.

Ci-dessous, le modèle HTML.

<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>

Et ci-dessous se trouve 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
    }
  }
});

Lorsque j'exécute les codes ci-dessus, je peux constater que la propriété show a changé. Cependant, v-if n'est pas mis à jour. Ne pouvons-nous pas utiliser array [index] pour v-if ou y a-t-il une autre raison?

15
Jiseung Roh

Le problème ne concerne pas v-if, C'est parce que Vue ne peut pas détecter directement les changements d'un élément de tableau, c'est l'une des limitations de JavaScript.

Ainsi, Vue fournit quelques fonctions d'assistance pour cela, comme Vue.set

Modifiez ce this.show[index] = !this.show[index]

à Vue.set(this.show, index, !this.show[index])

alors ça devrait marcher.

Vue.set N'est pas la seule solution, il existe plusieurs façons d'y parvenir, au cas où vous voudriez le savoir.

Vous pouvez utiliser des méthodes natives de tableau JavaScript, Vue accrochera ces méthodes afin qu'il puisse détecter les changements.

Voici l'exemple d'utilisation de .splice

this.show.splice(index, 1, !this.show[index])

Une autre façon consiste à remplacer entièrement le tableau. Si vous utilisez ES6, vous pouvez utiliser l'opérateur d'étalement pour cloner le tableau facilement:

this.show[index] = !this.show[index]
this.show = [...this.show]

.map Fonctionnera également car il renvoie un nouveau tableau

this.show = this.show.map((el, i) =>
  i === index ? !el : el
)
23
CodinCat

Vous pouvez utiliser un JS objet au lieu d'un tablea et obtenir le même effet. En d'autres termes, remplacez show: [false, false, false], avec show: {0:false, 1:false, 2:false},.

1
Igor de Lorenzi

Dans le composant dans les méthodes, vous pouvez utiliser:

this.$set(this.show, index, !this.show[index])
0
user5510975