Почему мой компонент Vue требует: key?

у меня есть небольшой Vue.JS компонент, который отображает значок любимой звезды. Нажав на значок "избранное" /unfavorites элемент. До сих пор я реализовал только часть пользовательского интерфейса, которая выглядит так:

<template>
  <div :key="favorite">
    <a v-on:click="toggleFavorite" style="cursor: pointer">
      <i v-show="favorite" class="text-warning fas fa-star"></i>
      <i v-show="!favorite" class="text-warning far fa-star"></i>
    </a>
  </div>
</template>

<script>
export default {
  data() {
    return {
      favorite: true,
    }
  },
  mounted() {
  },
  methods: {
    toggleFavorite() {
      this.favorite = !this.favorite
    }
  },
  props: ['team-id'],
}
</script>

<style scoped>
</style>

как вы можете видеть, логика довольно проста.

это работает хорошо, но меня беспокоит то, что, если я удалю :key свойство из моего шаблона, значок не обновляется, когда я нажимаю на него (хотя я проверил, что базовый собственность is действительно правильно обновить). Добавление :key заставляет его работать, я думаю, потому что он заставляет Vue.js для полного повторного отображения компонента, когда favorite обновляется.

Почему это происходит? Я довольно новичок в мире фреймворков JS, поэтому простите любые очевидные вещи, которые я мог бы пропустить. Я провел некоторое исследование в интернете, но не смог найти объяснения. Я просто хочу убедиться, что я делаю все правильно, а не просто взламываю проблему здесь.

4 ответов


похоже, что это общая проблема FontAwesome CSS независимо от структуры. Существует проблема на github и здесь та же проблема с react https://github.com/FortAwesome/Font-Awesome/issues/11967

чтобы доказать это, вот упрощенная версия того же примера, но с использованием bootstrap icons

new Vue({
  el: '#app',
  data() {
    return { 
      fav: true
    }
  }
});
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"
></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

<div id="app">
  <div>
    <a v-on:click="fav = !fav" style="cursor: pointer">
      <i v-show="fav" class="glyphicon glyphicon-star"></i>
      <i v-show="!fav" class="glyphicon glyphicon-star-empty"></i>
    </a>
  </div>
</div>

Vue патчи с виртуальным DOM, когда это необходимо. То есть, когда vue обнаруживает изменения на DOM, он исправляет их для более быстрой производительности. И исправление в DOM не изменит значок или изображение. Вместо этого вам нужно заменить DOM.

таким образом, vue предоставляет нам путь, когда нам нужно изменить DOM путем замены метода, мы можем использовать :key привязка.

и :key binding можно использовать для принудительной замены элемент / компонент вместо повторного использования.

следующий весь HTML div будет заменен всякий раз, когда есть изменение в favorite данные, как мы :key привязка к нему:

<div :key="favorite">
    <a v-on:click="toggleFavorite" style="cursor: pointer">
      <i v-show="favorite" class="text-warning fas fa-star"></i>
      <i v-show="!favorite" class="text-warning far fa-star"></i>
    </a>
  </div>

вот почему vue насильно позволяет нам использовать :key привязка внутри цикла, поскольку необходимо заменить элементы внутри цикла всякий раз, когда он обнаруживает изменения в data. Это делается обязательным из 2.2.0+ и ESLint также реализовали эту функцию, чтобы, если вы Мисс :key привязка внутри цикла, затем вы увидите ошибку в этой строке при использовании редактора, поддерживающего eslint, чтобы вы могли исправить ошибку.

просто мнение, строгое требование :key привязка должна быть удалена из vue, поскольку нам может понадобиться цикл predefined data и не хотите менять DOM, но мы все еще используем v-for петли для перечисления больших данных. Но это может быть редкий случай.


внимательно прочитайте документация :комбинации клавиш и тогда у вас появится идея.

на :key привязка может быть полезна, если вы хотите:

правильно триггерные крючки жизненного цикла компонента

триггер переходы


  1. использовать :key привязка для замены DOM. Помните, что это замедляет производительность, поскольку она заменяет весь DOM, который привязан к элементу.
  2. не используйте :key привязка, когда вы не хотите заменять DOM или вы думаете, что нет data обнаружение изменений, необходимых. Эта воля позвольте vue работать лучше без :key привязка.

вам не нужен ключ:, это необходимо только в V-для циклов. Я бы предложил вам удалить его и заменить ваше v-шоу директивой v-if и v-else.

  <i v-if="favorite" class="text-warning fas fa-star"></i>
  <i v-else class="text-warning far fa-star"></i>

v-Если удаляет и добавляет раздел в DOM, тогда как v-show просто скрывает его, чтобы таким образом решить вашу проблему


Ok Я думаю, что проблема здесь в том, что вы меняете свой корневой объект данных. Чтобы сохранить реактивность, не следует изменять корневой объект данных после создания экземпляра Vue.

здесь код в простом Vue. Мне не нужен был ключ, чтобы заставить его работать. Я бы сохранил :ключ для внутренних петель.

разметки

<div id="vueRoot">
  <a v-on:click="toggleFavorite" style="cursor: pointer">
    <i v-show="store.favorite" class="text-warning fas fa-star">Fav</i>
    <i v-show="!store.favorite" class="text-warning far fa-star">Not fav</i>
  </a>
</div>

код

vm = new Vue({
  el : "#vueRoot",
  data() {
    return { store :{
      favorite: true
    }}
  },
  mounted() {
  },
  methods: {
    toggleFavorite() {
      this.store.favorite = !this.store.favorite
    }
  }
}
);

Это рабочий пример с минимальными изменениями. От чего вы показали нам, вы должны просто иметь элемент , а затем делать то, что хотите, с динамическим списком классов...

<i :class="['text-warning','fa-star',store.favorite?'fas':'far']"></i>