1

deleteData()从同时用于创建动态组件的对象数组中删除元素后,我无法处理正确的渲染。

元素被正确删除,但它表现得好像组件不知道它应该刷新,并且 Vue 不知道数据已更改。

在chrome Vue扩展中,移除了正确的元素,但是DOM中的Vue移除了最后一个element()

视图:

 <template>
  <b-container>
    <SectionSelector :AddSection="AddSection"/>
      <component v-for="(section, index) in sections"
              :key="index"
              :is="section.type"
              :sectionIndex="index"
              :sectionData="section[index]"
              :deleteData="deleteData"
              @sectionDataEmit="sectionDataEmit"/>
  </b-container>
</template>

<script>
  import SectionSelector from './components/SectionSelector.vue';
  import FullText from './components/sections/FullText.vue';
  import FullImage from './components/sections/FullImage.vue';
  import ImageRightTextLeft from './components/sections/ImageRightTextLeft.vue';
  import ImageLeftTextRight from './components/sections/ImageLeftTextRight.vue';
  import Vue from 'vue'

  export default {
    data() {
      return {
        sections: []
      }
    },
    methods: {
      AddSection(sectionData) {
        this.sections.push(sectionData);
      },
      updateSection(sectionIndex, sectionData) {
        Vue.set(this.sections, sectionIndex, sectionData);
      },
      sectionDataEmit(emitData) {
        Vue.set(this.sections, emitData.position, emitData.content);
      },
      deleteData(index) {
        // eslint-disable-next-line 
        console.log(index)
        this.$delete(this.sections, index);
      }
    },
    components: {
      SectionSelector,
      FullText,
      FullImage,
      ImageRightTextLeft,
      ImageLeftTextRight
    }
  }
</script>

零件:

    <template>
  <b-row>
    <h3>Full text {{ sectionIndex+1 }}</h3>
    <b-button variant="danger"
            @click="deleteButton(sectionIndex)">delete</b-button>
    <b-textarea :value="sectionData" 
              @input="sectionDataEmit" />
  </b-row>
</template>

<script>
  export default {
    props: ['sectionIndex', 'sectionData', 'deleteData'],
    methods: {
      sectionDataEmit(value) {
        let emitData = {
          position: this.sectionIndex,
          content: {
            type: 'FullText',
            fields: {
              text: value
            }
          }
        }
        this.$emit('sectionDataEmit', emitData)
      },
      deleteButton(index) {
        this.deleteData(index)
      }
    }
  }
</script>

在删除数据()之前

在删除数据()之后

4

1 回答 1

1

由于您正在尝试呈现有状态组件的列表而不是简单/简单的 DOM 节点,因此将作为真正唯一的属性变得至关重要。使用索引作为关键属性值并不能保证唯一性。你可以在这里阅读更多关于它的信息。

为什么会这样?

Vue.js 在内部使用虚拟 DOM (VDOM) 来高效渲染 UI。所以当你的数组改变时,Vue.js 使用 VDOM 来更新 DOM。VDOM 不知道 Vue.js 组件或其状态。因此,VDOM 有可能将错误的 DOM 元素分配给组件。这是关键属性帮助 Vue.js 跟踪组件及其 DOM 元素的地方。

当你使用indexforkey属性时会发生什么?

想象一下,您使用索引作为关键属性。现在,您最初在一个数组中有五个要渲染的项目。对于每个项目,它都会实例化一个组件实例。所以,五个 DOM 元素和五个组件

  • component0 - DOM0 - 索引 0
  • component1 - DOM1 - 索引 1
  • component2 - DOM2 - 索引 2
  • component3 - DOM3 - 索引 3
  • component4 - DOM4 - 索引 4

现在,假设您使用 splice 方法删除了第三个项目:

array.splice(2, 1);

做完上述操作后,数组长度从 5 变为 4。对于 vue.js,它是第 4 个索引,即第 5 项没有了。索引 2 仍然存在,从未消失;因此其关联的component2仍然有效。所以相反,它会杀死索引 4引用的component4(因为该数组不再存在索引 4)。简而言之,它破坏了错误的组件。

  • component0 - DOM0 - 索引 0
  • component1 - DOM1 - 索引 1
  • component2 - DOM2 - 索引 2
  • component3 - DOM3 - 索引 3
  • component4 - DOM4 - 索引 4

解决方案?

您应该有一些唯一的键,id,每个键sectionData在列表中唯一地标识自己。想象一下,如果你必须对sections数组进行排序,那么即使在排序之后,唯一的 id 应该仍然是相同的(使用id索引将在重新排序后更改它的 id,并且事情会被 VDOM 弄乱)。

在这个 Vue.js 论坛帖子上阅读更多关于这些规则的信息。

于 2019-05-30T06:22:48.393 回答