【问题标题】:Why does vuejs replicates its v-model data when the v-model is referenced within a computed property?为什么 vuejs 在计算属性中引用 v-model 时会复制其 v-model 数据?
【发布时间】:2021-03-21 04:12:59
【问题描述】:

在以下代码中:

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;(下面 Codepen 中的第 16 行)可以解决此问题。

我怀疑this.selected 以某种方式取消引用它自己的值,然后无法验证以前选择的项目的外观。

这是一个解决手头问题的 Codepen:https://codepen.io/MichaelKatz/pen/vYXXdgb

在我的真实场景中,我需要根据之前所做的选择(即删除/重新添加项目)过滤和操作列表中的项目。 我通过使用计算出的item 属性来做到这一点,该属性从先前选择的项目中派生其内容,来自selected v-model,我当前的解决方案将要求我JSON.stringify 我的所有对象,基本上使它们有价值-基于字符串来控制事情。

【问题讨论】:

    标签: javascript vue.js vuetify.js v-model


    【解决方案1】:

    似乎在过滤它所引用的项目时访问 v-model 会创建对其中对象的取消引用。

    我能想到的最佳解决方案是添加一个额外的计算属性,该属性将包含涉及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;
        }
      }
    }
    

    【讨论】:

      【解决方案2】:

      v-model 似乎不适用于对象

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

      并创建一个新的计算属性来“水合”这些 id:

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

      Updated Codepen

      【讨论】:

      • 如果 this.selected 将用于过滤数据 - 对于大于 100 左右的列表,它将导致调用堆栈超过其最大值。它还将导致添加的每个项目和selectedItems 的初始计算立即降低性能。请参阅下面的高性能解决方案。
      【解决方案3】:

      在我看来,问题在于你使用了multiple 属性,它允许多选。

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

      只需删除它即可解决您的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-29
        • 2018-01-09
        • 2019-08-26
        • 2020-06-08
        • 1970-01-01
        • 1970-01-01
        • 2015-10-15
        相关资源
        最近更新 更多