Как понять ключи в vue?

Vue.js
Как понять ключи в vue?

Насколько нам известно, роль ключа заключается в следующем.

  • Когда v-for проходит, используйте id, uuid и т.п. в качестве ключей для уникальной идентификации узлов, чтобы ускорить визуализацию виртуального DOM.
  • Для данных, которые отзывчивая система не отслеживает, используйте метку времени, сгенерированную +new Date(), в качестве ключа для ручного запуска повторного рендеринга.

Обычно можно увидеть одну и ту же сцену, но вторая сцена выглядит следующим образом:

<div :key="rerender">
    <span>Hello Vue.js !</span>
    <complexComponent :propObj="propObj" :propArr="propArr" ></complexComponent>
</div>

refresh(){
    this.rerender = + new Date();
}

Итак, какова релевантная точка знаний о ключевом значении?

  • Официальные точки знаний API
  • Каково обоснование двух приведенных выше сценариев использования?
  • Помимо ключей, есть ли другой способ принудительно обновить DOM?
  • использованная литература

Официальные точки знаний API

  • В Vue.js key — это одно из 6 специальных свойств key, ref, is, slot, slot-scope, scope.
  • Значение ключа может быть числом или строкой.
  • Ключ в основном используется в алгоритме виртуального DOM Vue в качестве подсказки для идентификации VNode при сравнении списка новых узлов и списка старых узлов.
  • Если вы не используете ключи, Vue будет использовать алгоритм, который сводит к минимуму перемещение элементов, и попытается как можно больше исправлять или повторно использовать элементы одного и того же типа в одном и том же месте.
  • Если используются ключи, Vue будет записывать элементы в соответствии с порядком ключей,Если элемент, у которого когда-то был ключ, больше не появляется, он будет удален или уничтожен напрямую.
  • Дети с одним и тем же родителем должны иметь уникальные ключи. Повторяющиеся ключи вызывают ошибки рендеринга.

Наиболее распространенное использование: v-for

<ul>
    <li v-for="item in items" :key="item.id">...</li>
</ul>

Наиболее распространенное использование 2: Принудительная замена элемента или компонента

  • Запустить жизненный цикл компонента
  • триггерный переход
<transition>
  <span :key="text">{{ text }}</span>
</transition>

Когда текст меняется,<span>будет заменен, но не исправлен, поэтому переход будет запущен. Мое понимание:При изменении текста изменяется ключ диапазона, то есть диапазон, который когда-то имел старый ключ, больше не отображается.Когда текст с новым значением используется в качестве ключа, появляется диапазон с новым ключом, тогда старый диапазон ключей будет удален, старый переход также будет удален, новый диапазон ключей запустит рендеринг, а новый переход запустится.

Каково обоснование двух приведенных выше сценариев использования?

В сочетании со знанием официального API, теперь оглядываясь на сцену в начале статьи поднята.

Сценарий 1: V-FOR, использование ID, UUID в качестве ключа, уникальный идентификационный узел ускоряет рендеринг виртуального DOM.

Отвечать:

  • Если вы не используете ключи, Vue будет использовать алгоритм, который сводит к минимуму перемещение элементов, и попытается как можно больше исправлять или повторно использовать элементы одного и того же типа в одном и том же месте.
  • Если используются ключи, Vue будет записывать элементы в соответствии с порядком ключей,Если элемент, у которого когда-то был ключ, больше не появляется, он будет удален или уничтожен напрямую.

Сценарий 2. Для данных, которые не отслеживаются реагирующей системой, используйте отметку времени, сгенерированную +new Date(), в качестве ключа для ручного запуска повторного рендеринга.

<div :key="rerender">
    <span>Hello Vue.js !</span>
    <complexComponent :propObj="propObj" :propArr="propArr" ></complexComponent>
</div>

refresh(){
    this.rerender = + new Date();
}

Отвечать:

  • Если используются ключи, Vue будет записывать элементы в соответствии с порядком ключей,Если элемент, у которого когда-то был ключ, больше не появляется, он будет удален или уничтожен напрямую.
  • После вызова метода обновления ключ div, содержащего span и complexComponent, меняется, то есть div, у которого когда-то был старый ключ, больше не появляется. с новым ключом. , тогда старый раздел ключей будет удален, старый диапазон и сложный компонент также будут удалены, новый раздел ключей вызовет рендеринг, новый диапазон,Визуализирует новый комплексный компонент с новыми родительскими объектами propObj и propArr.

думать:

  1. Почему они называются propObj и propArr?
  2. Визуализирует новый комплексный компонент с новыми родительскими объектами propObj и propArr.Почему смело?

Поскольку obj и arr в Vue.js не могут обнаруживать изменения данных, obj — это добавление и удаление атрибутов (причина в том, что сеттер не срабатывает для добавления и удаления, а наблюдатель не сообщает внешнему миру об обновлении), и arr — элемент в массиве Переназначить или изменить свойство length (причина в том, что метод изменения самого массива не используется, перехватчик цепочки прототипов массива не срабатывает, а наблюдатель не сообщает внешнему миру об обновлении) . так! Назначая новый ключ, удаляя старый ключ div, визуализируя новый ключ div, propObj и propArr снова запускают жизненный цикл в компоненте complexComponent и выполняют повторный рендеринг. **В настоящее время js-переменные propObj и propArr родительского компонента фактически получили новые значения, но DOM не срабатывает или VNode перерисовывается. **Вам необходимо принудительно обновить, обновив ключ.Говоря о forceUpdate, вы можете принудительно обновить DOM вручную через $forceUpdate().

Помимо ключей, есть ли другой способ принудительно обновить DOM?

Сценарий: родительский компонент изменяет данные, переданные дочернему компоненту, и обновление данных массива не обновляется в соответствии с this.$set. что делать?

this.productImages.forEach((product) => {
  if (product.productId in this.productsState) {
    product.status = this.productsState[product.productId];
  }
});

В чем причина того, что не выполняется повторный рендеринг без использования this.$set для назначения данных?Во Vue.js обнаружение изменений для Array реализовано путем перехвата прототипов. Он также перехватывает методы push, pop, shift, unshift, splice, sort, reverse, fill и copyWithin для изменения содержимого самого массива. а такжеproduct.status = this.productsState[product.productId];Ни один из прослушиваемых методов, которые изменяют сам массив, не запускается, поэтому повторной визуализации не происходит.

  • обновить ключ компонента
  • Метод $forceUpdate

обновить ключ компонента

1. Куда лучше добавить этот ключ?

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

2. Какое значение ключа используется?

Теперь это грубая отметка времени +new Date() в качестве значения ключа. Вы также можете использовать значение двусторонней привязки в качестве значения ключа, чтобы убедиться, что старое и новое значения ключа различаются.

3. Каков принцип ключа?

Алгоритм виртуального DOM vue.js должен найти тот же vNode, что и новый vNode, из старого списка vNode при обновлении vNode.Если в этом процессе задан ключ атрибута, процесс будет намного быстрее. Другие подробности см. выше.

Метод $forceUpdate

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

// $forceUpdate源码
Vue.prototype.$forceUpdate = function () {
  const vm: Component = this
  if (vm._watcher) {
    vm._watcher.update()
  }
}
// update源码
/**
 * Subscriber interface.
 * Will be called when a dependency changes.
 */
update () {
  /* istanbul ignore else */
  if (this.lazy) {
    this.dirty = true
  } else if (this.sync) {
    this.run()
  } else {
    queueWatcher(this)
  }
}
1. Анализ принципа возможности обновления $forceUpdate

product.status = this.productsState[product.productId];после,На самом деле dep изменился в это время., но отзывчивая реализация массива Vue.js — это способ перехвата метода цепочки прототипов, и это изменение не обнаруживается, поэтому оно не будет автоматически перерисовываться, и обновление не будет запущено. поэтому мыС помощью $forceUpdate вызывается метод update в наблюдателе, содержащем dep, для достижения повторного рендеринга..

2. Можно ли прослушивать события в дочерних компонентах, отправлять события из родительского компонента и обновлять только дочерние компоненты?

Не можем. Поскольку dep является наблюдателем и dep родительского компонента, а не дочернего компонента, this.productImages родительского компонента не обнаруживается и не обновляется в режиме реального времени, а не проблема дочернего компонента.

использованная литература

vuejs.org/v2/api/#key v UE JS.org/V2/API/#VM-… v UE JS.org/V2/expensive/co…

Оригинальная ссылка:GitHub.com/Фрэнк Кай/fr…

Я с нетерпением жду возможности пообщаться с вами и вместе добиться прогресса. Приглашаем вас присоединиться к созданной мной технической дискуссионной группе, тесно связанной с фронтенд-разработкой:

Стремитесь стать отличным front-end инженером!