Почему vuejs реплицирует свои данные v-модели, когда ссылка на v-модель содержится в вычисляемом свойстве?

#javascript #vue.js #vuetify.js #v-model

#javascript #vue.js #vuetify.js #v-модель

Вопрос:

В следующем коде:

JS

 const App = {
  template: '#app-template',
  data: () => ({
    selected: [],
    items: Array.from({length: 50}, (x, i) => i 1).map(i => ({
      id: i ,
      name: `Item ${i}`,
      subtitle: `Subtitle ${i}`
    }))
  }),
  computed: {
    parsedItems() {
      this.selected;
      return this.items.map(item => ({
        someValue: 3,
        ...item
      }));
    }
  }
}


new Vue({
  vuetify: new Vuetify(),
  render: h => h(App)
}).$mount('#app')
 

HTML

 <script type="text/x-template" id="app-template">
  <v-app>
    {{selected}}
    <v-container>

        <v-virtual-scroll
          :items="parsedItems"
          :item-height="65"
          height="500"
        >
          <template v-slot="{ item, index }">
           <v-list-item-group
             v-model="selected"
             multiple
           >
            <v-list-item :key="item.id" :value="item">
              <v-list-item-action>
                <v-checkbox
                  :input-value="selected.includes(item.id)"
                  color="primary"
                />
              </v-list-item-action>
              <v-list-item-content>
                <v-list-item-title>
                  Index: {{ index }} {{ item.name }}
                </v-list-item-title>
                <v-list-item-subtitle>
                  {{ item.subtitle }}
                </v-list-item-subtitle>
              </v-list-item-content>
            </v-list-item>
           </v-list-item-group>
          </template>
        </v-virtual-scroll>
    </v-container>
  </v-app>
</script>

<div id="app"></div>

 

Когда любой из флажков, которые я установил или снял, selected v-model всегда добавляет еще один экземпляр, хотя ранее он уже содержал один.

Удаление this.selected; (строка 16 в Codepen ниже) устраняет проблему.

Я подозреваю, что this.selected это каким-то образом разыменовывает свои собственные значения, а затем не может проверить внешний вид ранее выбранных элементов.

Вот Codepen с рассматриваемой проблемой: https://codepen.io/MichaelKatz/pen/vYXXdgb

В моем реальном сценарии мне нужно фильтровать и манипулировать элементами в списке в соответствии с ранее сделанными выборками (т.е. Удалять / повторно добавлять элементы). Я делаю это, используя вычисляемое item свойство, которое извлекает свое содержимое из ранее выбранных элементов, из selected v-модели, и мое текущее решение потребует от меня JSON.stringify всех моих объектов, по сути, превращая их в строки на основе значений, чтобы держать все под контролем.

Ответ №1:

Похоже, v-model он не работает с объектами

 <v-list-item :key="item.id" :value="item">    <!-- change this -->
<v-list-item :key="item.id" :value="item.id"> <!-- into this   -->
 

И создайте новое вычисляемое свойство для «увлажнения» этих идентификаторов:

 selectedItems() {
  return this.selected.map(id => this.parsedItems.find(x => x.id === id))
}
 

Обновленный Codepen

Комментарии:

1. Если this.selected будет использоваться для фильтрации данных — это приведет к тому, что стек вызовов превысит свой максимум для списков размером более 100 или около того. Это также приведет к немедленному снижению производительности для каждого добавленного элемента и для первоначального вычисления selectedItems . Смотрите мое эффективное решение ниже.

Ответ №2:

Похоже, что доступ к v-модели при фильтрации элементов, на которые она ссылается, создает отмену ссылок на объекты внутри нее.

Лучшим решением, которое я мог придумать, было добавление дополнительного вычисляемого свойства, которое будет содержать логику this.selected .

Это действительно решило проблему для меня.

   computed: {
    parsedItems() {
      return this.items.map(item => ({
        someValue: 3,
        ...item
      }));
    },
    filteredItems() { // adding another computed property while using this.selected
      this.selected;
      return this.parsedItems;
    }
  }
}
 

Ответ №3:

С моей точки зрения, проблема в том, что вы использовали multiple реквизит, который допускает множественный выбор.

       <template v-slot="{ item, index }">
       <v-list-item-group
         v-model="selected"
         multiple
       >
 

Простое удаление этого решит вашу проблему.