Странное поведение при переключении отфильтрованных результатов в Vue.js - PullRequest
1 голос
/ 28 сентября 2019

У меня есть список элементов {name: 'bla', done:false}, который фильтруется свойством done для отображения.

[_] element1
[_] element2

Когда я нажимаю на флажок, свойство done изменяется, и поэтому этот элемент исчезает.Странно то, что когда я нажимаю на первый элемент, он исчезает, и второй элемент отображается, но с установленным флажком!

[v] element2 

Примечание - элемент видим (все в порядке), но как-то проверен(не в порядке).

Как этого избежать?Я не хочу чек без щелчка.Я даже не знаю, какие слова в гугле, такой странный случай:)

Рабочий пример ошибки - попробуйте проверить первый отфильтрованный элемент .Другая проблема заключается в том, что он работает корректно как фрагмент кода здесь, в SO, но работает неправильно в jsfiddle (и моем приложении).

Примечание: ниже вы можете увидеть желаемое поведение.Скрипка для неправильного.

new Vue({
  el: "#app",
  computed:{
   todosfiltered: function(){
   return this.todos.filter(function(elem){
   return !elem.done;
   });
   },
  },
  data: {
    todos: [
      { text: "Learn JavaScript", done: false, tip:true },
      { text: "Learn Vue2", done: false, tip:false, },
      { text: "Play around in JSFiddle", done: true, tip:false },
      { text: "Build something awesome", done: true, tip:false }
    ]
  },
  methods: {
  	toggle: function(todo){
    	todo.done = !todo.done
    }
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.15/vue.js"></script>

<div id="app">
  <h2>Todos:</h2>
  <ol>
    <li v-for="todo in todos">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }}
        </span>
      </label>
    </li>
  </ol>
  <h2>
  filtered elements:
  </h2>
  <ol>
    <li v-for="(todo, key) in todosfiltered">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }} <span v-if="todo.tip">&lt;-- click this checbox</span>
        </span>
      </label>
    </li>
  </ol>
</div>

1 Ответ

3 голосов
/ 28 сентября 2019

В этом случае это вызвано отсутствием свойства key в элементе, на который выполняется циклическое переключение.Всегда включайте ключ, чтобы предотвратить подобные проблемы, и убедитесь, что ключ уникален.

Я использую todo.text здесь, но если текст не уникален, вы можете столкнуться с теми же ошибками рендеринга.Вместо этого вы можете добавить свойство id, чтобы различать их.

<h2>
  filtered elements:
  </h2>
  <ol>
    <li v-for="todo in todosfiltered" :key="todo.text">
      <label>
        <input type="checkbox"
          v-on:change="toggle(todo)"
          v-bind:checked="todo.done">

        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }} <span v-if="todo.tip">&lt;-- click this checbox</span>
        </span>
      </label>
    </li>
  </ol>

И, наконец, можно использовать индекс цикла for, но это менее чем оптимально из-за способа, которым Vuejsобрабатывает перерисовку .При использовании индекса удаление элемента из списка приведет к изменению индекса всех элементов после него, что приведет к повторной визуализации для всех из них.Это не имеет значения для небольших наборов данных, но может повлиять на большие списки.

...