如何从数组中删除动态组件

时间:2019-05-28 20:52:40

标签: javascript vue.js vue-dynamic-components

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

该元素已正确删除,但是它的行为就像组件不知道应该刷新一样,而Vue不知道数据已更改。

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

Vue:

 <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>

before deleteData()

after deleteData()

1 个答案:

答案 0 :(得分:0)

由于您要呈现状态组件列表,而不是简单/简单的DOM节点,因此作为真正独特的属性变得至关重要。使用索引作为键属性值不能保证唯一性。您可以详细了解here

为什么会这样?

Vue.js在内部使用虚拟DOM(VDOM)来有效呈现UI。因此,当阵列发生变化时,Vue.js使用VDOM更新DOM。 VDOM不了解Vue.js组件或其状态。因此,VDOM可能会为组件分配错误的DOM元素。这是 key 属性帮助Vue.js跟踪组件及其DOM元素的地方。

index属性用于key会发生什么?

想象一下,您已经使用索引作为键属性。现在,您最初在阵列中有五个项目要渲染。对于每个项目,它实例化一个组件实例。因此,五个DOM元素和五个组件

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

现在,假设您使用拼接方法删除了第三项:

array.splice(2, 1);

完成上述操作后,数组长度从5变为4。对于vue.js,它是第4个索引,即第五项不见了。索引2仍然存在并且从未消失;因此,其关联的 component2 仍然有效。因此,它去掉了由 index 4 引用的 component4 (因为该数组不再存在索引4)。简而言之,它会破坏错误的组件。

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

解决方案?

对于每个id,您应该有一个唯一的密钥sectionData,以便在列表中唯一标识自己。想象一下,如果您必须对sections数组进行排序,那么即使在排序后,该唯一ID仍应相同(对 id 使用 index 会在重新排序后更改其ID事情就被VDOM搞砸了。

详细了解these rules here on this Vue.js forum thread