为啥 Vue 渲染组件不正确?

Posted

技术标签:

【中文标题】为啥 Vue 渲染组件不正确?【英文标题】:Why does Vue render component incorrectly?为什么 Vue 渲染组件不正确? 【发布时间】:2021-05-28 08:22:33 【问题描述】:

以下是错误示例。

重现问题:添加 3 项并删除第二项。

里面的所有东西都被正确删除了。这可以从下面的文本渲染中看出。但组件显示不正确。为什么?这是一个错误吗?

我尝试使用附加属性进行条件渲染,尝试覆盖对元素数组和数组内部的引用 - 没有结果。

Vue.component('selected-material', 
  props: [
    'value'
  ],
  template: `
    <div>
      <v-autocomplete
        v-model="local"
        :items="materials"
        item-text="name"
        return-object
        autocomplete="new-password"
        @change="input"
      />
    </div>
  `,
  data() 
    return 
      local: this.value,
      materials: [
          id: 1,
          name: 'mat-1',
          q: 1
        ,
        
          id: 2,
          name: 'mat-2',
          q: 1
        ,
      ],
    ;
  ,
  methods: 
    input() 
      this.$emit('input', this.local);
    ,
  ,
)

Vue.component('add-board', 
  props: [
    'value'
  ],
  template: `
    <div>
      <v-container fluid class="my-0 py-0">
        <v-row class="my-0 py-0">
          <v-col class="my-0 py-0">
            <selected-material
              v-model="local.material"
            />
          </v-col>
          <v-col class="my-0 py-0">
            <v-text-field
              class="my-0 py-0"
              v-model="local.material.q"
            />
          </v-col>
          <v-col class="my-0 py-0">
            <v-row class="my-0 py-0">
              <v-col class="my-0 py-0">
                <v-btn
                  class="my-0 py-0"
                  color="success"
                  icon
                  @click="append"
                >
                  <v-icon>mdi-plus</v-icon>
                </v-btn>
              </v-col>
              <v-col class="my-0 py-0">
                <v-btn
                  class="my-0 py-0"
                  color="error"
                  icon
                  @click="remove"
                >
                  <v-icon>mdi-minus</v-icon>
                </v-btn>
              </v-col>
            </v-row>
          </v-col>
        </v-row>
      </v-container>
    </div>
  `,
  data() 
    return 
      local: this.value,
    ;
  ,
  methods: 
    input() 
      this.$emit('input', this.local);
    ,
    append() 
      this.$emit('append');
    ,
    remove() 
      this.$emit('remove', this.local.id);
    ,
  ,
)

new Vue(
  el: '#app',
  vuetify: new Vuetify(),
  data() 
    return 
      boards: [],
    ;
  ,
  mounted() 
    this.append();
  ,
  methods: 
    append() 
      this.boards.push(
        id: Date.now(),
        material: 
          id: 1,
          name: 'mat-1',
          q: 1
        ,
      );
    ,
    remove(id) 
      if (this.boards.length !== 1) 
        const index = this.boards.findIndex(board => board.id === id);

        this.boards.splice(index, 1);
      
    ,
  ,
)
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Material+Icons" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>

<div id="app">
  <v-app>
    <v-main>
      <v-row v-for="(board, index) in boards" :key="index">
        <v-col>
          <add-board :key="index" v-model="boards[index]" @append="append" @remove="remove" />
        </v-col>
      </v-row>

      <v-row v-for="(board, index) in boards" :key="`_$index`">
        <v-col>
           board.id  |  board.material.q 
        </v-col>
      </v-row>
    </v-main>
  </v-app>
</div>

UPD

替换为ID后:

【问题讨论】:

【参考方案1】:

v-for 列表中删除项目时,如果您不想重复使用 DOM,请务必使用每个项目唯一的 key。如果您使用index 并删除一个项目,则下一个项目将采用其索引,因此 Vue 会重用已删除项目的 DOM。

使用id 作为键,因为这似乎是唯一的:

<v-row v-for="(board, index) in boards" :key="board.id">

另外,检查&lt;v-text-field&gt; 上的v-model,看来您可能打算使用local.material.q 而不是local.q

<v-text-field
  class="my-0 py-0"
  v-model="local.material.q"
/>

【讨论】:

谢谢。它在 sn-p 中工作,但在我项目的组件中它更重并且 vue 崩溃。 不要更改子组件中的 id!)

以上是关于为啥 Vue 渲染组件不正确?的主要内容,如果未能解决你的问题,请参考以下文章

Vue之重新渲染组件的正确方式

为啥 VueJS 组件在导入/组件调用后不渲染标签?

为啥不在 Vue 和 Vue Router 生产环境中渲染我的组件?

vue 相邻自定义组件渲染错误正确的打开方式

vue为啥要求组件模板只能有一个根元素

vue3动态组件为啥只能点击切换一次组件