как удалить динамические компоненты из массива - PullRequest
0 голосов
/ 28 мая 2019

Я не могу справиться с правильным рендерингом после удаления элемента с помощью deleteData() из массива объектов, который одновременно служит для создания динамических компонентов.

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

В расширении Chrome Vue правильный элемент удаляется, но Vue в DOM удаляет последний элемент ()

Вю:

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

до удаления данных ()

после deleteData ()

1 Ответ

0 голосов
/ 30 мая 2019

Поскольку вы пытаетесь отобразить список компонентов с состоянием, а не простых / простых узлов DOM, становится крайне важным иметь ключ в качестве действительно уникального атрибута.Использование индекса в качестве значения ключевого атрибута не гарантирует уникальность.Подробнее об этом можно прочитать здесь .

Почему это происходит?

Vue.js использует Virtual DOM (VDOM) внутри для эффективной визуализации пользовательского интерфейса.Поэтому, когда ваш массив изменяется, Vue.js использует VDOM для обновления DOM.VDOM не знает ни компонента Vue.js, ни его состояния.Таким образом, существует вероятность того, что VDOM может назначить неправильный элемент DOM для компонента.Именно здесь ключевой атрибут помогает 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 все еще действителен.Поэтому вместо этого он убивает component4 , на который ссылается index 4 (поскольку индекс 4 больше не существует для этого массива).Короче говоря, он уничтожает неправильный компонент.

  • component0 - DOM0 - индекс 0
  • component1 - DOM1 - индекс 1
  • component2 - DOM2 - индекс 2
  • component3 - DOM3 - индекс 3
  • component4 - DOM4 - индекс 4

Решение?

У вас должно быть несколько уникальныхid, для каждого sectionData, чтобы уникально идентифицировать себя в списке.Представьте себе, если вам нужно отсортировать массив sections, этот уникальный идентификатор должен оставаться неизменным даже после сортировки (использование index для id изменит свой идентификатор после переупорядочения, и все будет запутанос VDOM).

Подробнее о этих правилах читайте в этой ветке форума Vue.js .

...