#vue.js
#vue.js
Вопрос:
После долгих испытаний и чтения дальше vue.js , Я взялся за свое первое приложение с компонентами и т. Д. Мне было сложно связать внешний объект с данными и выяснить, в каких условиях Vue связывает эти внешние объекты с атрибутами data / computed / watch / props. Я столкнулся с некоторыми странными сюрпризами с моими компонентами, и я решил изучить некоторые случаи с codepen. Моя главная проблема заключается, например, в том, что когда у вас есть a: b,
в data
разделе и b
является внешним объектом, таким как значение, массив, объект, простой или глубоко вложенный, как это работает с привязкой к DOM в {{a}}
и v-bind
в основном.
К моему удивлению во время этих тестов, я первым увидел {{b}}
, что тоже реагирует. Почему бы и нет, потому b
что объявлено в data
разделе. Все становится странным, когда я попробовал {{c}}
, где c
находится внешняя сущность, отсутствующая где-либо в Vue
объекте. DOM тоже реагировал на c
!
Что еще более странно, я наблюдал это явление только в части HTML / template: watch
реагирует только на a
и computed
на a
и b
, но не на c
.
Я также props
заметил, что они реагируют на a
, b
, и c
.
Все эти тесты объединены в codepen, где я устанавливаю перемещение своих внешних данных на a setInterval
. Это здесь: https://codepen.io/Djee/pen/qwXjRw
В более широком смысле я не нашел ни одной статьи или материала, посвященных тем аспектам, о которых я впервые упоминаю, и, в частности, не такого рода автоматическое связывание объектов, непосредственно связанных с handlebars и работающих без упоминания где-либо в Vue
объекте. Я что-то пропустил? Есть ли какой-либо материал, исследующий / объясняющий эти аспекты? Спасибо за помощь.
PS: в моем проекте я обнаружил, что использование this.$watch(cb, {deep: true});
created()
функции in является более мощным, чем watch
. Еще одна странность для меня, не включенная в этот codepen, на момент написания. Может быть, я добавлю это.
Ответ №1:
Я думаю, что это ключевая часть вашего вопроса:
как это работает с привязкой к DOM
То, как вы написали свой codepen, делает это похожим на простой вопрос, но здесь задействовано несколько этапов, которые не сразу очевидны.
- При создании экземпляра Vue содержимое вашего
container
элемента используется в качестве шаблона. Затем сами узлы DOM удаляются. Это важно понимать, поскольку оно значительно отличается от того, как работают многие другие фреймворки. Вы ничего не привязываете к этим узлам DOM, они просто шаблон. - Затем этот шаблон компилируется в
render
функцию. Именно этуrender
функцию Vue вызовет для визуализации компонента. - Во время рендеринга
render
функция возвращает виртуальные узлы DOM (VDOM). Некоторые из этих узлов будут соответствовать элементам HTML, в то время как другие будут ссылаться на дочерние компоненты. Дочерний компонент будет отображаться по очереди, и в конечном итоге, как только все компоненты будут отображены, все сведется только к узлам HTML VDOM. - Во время первоначального рендеринга эти узлы HTML VDOM преобразуются непосредственно в HTML DOM. Во время обновлений (повторного рендеринга) новый VDOM сравнивается с предыдущим VDOM, и фактический DOM обновляется только там, где произошли изменения.
С точки зрения реактивности, render
это очень похоже на вычисляемое свойство. Любые реактивные данные, к которым прикасается render
функция, Будут отслеживаться. Если эти данные впоследствии изменятся, это вызовет повторный рендеринг этого компонента.
Любые данные, которые не реагируют, не будут отслеживаться. Обновление этих данных не приведет к повторному рендерингу, не обновит вычисляемые свойства и не вызовет никаких watch
прослушивателей.
В вашем примере у вас есть один большой шаблон, который будет скомпилирован до одной render
функции. Если какие-либо из реактивных данных изменятся, это вызовет повторный рендеринг. Это запустит всю render
функцию и создаст новое дерево VDOM. Доступ к данным осуществляется по мере необходимости и будет включать как реактивные, так и нереактивные данные.
Однако, если вы просто измените нереактивные данные, тогда нет ничего, что могло бы вызвать повторный рендеринг. В этом случае render
функция не будет вызвана, и никаких изменений DOM не произойдет.
Не позволяйте имени v-bind
сбивать вас с толку. Это просто означает «это выражение JavaScript» и не обязательно имеет какое-либо отношение к созданию зависимости. Зависимости отслеживаются на уровне render
функции, и нет специальной обработки для привязки зависимостей непосредственно к их узлам DOM. Если какая-либо зависимость изменится, Вся render
функция будет запущена повторно. Это не так дорого, как кажется, поскольку render
функция только создает VDOM. Дорогостоящий процесс обновления DOM будет использовать VDOM diffing / updating для внесения только минимальных изменений, необходимых для обновления узлов DOM, которые в этом нуждаются. Прямая связь между данными и DOM, которая, по-видимому, существует в шаблоне, не сохраняется после выполнения шаблона.
Вычисляемые свойства работают аналогичным образом. Их значения кэшируются и пересчитываются только при обновлении реактивной зависимости. Если у них есть нереактивная зависимость, это не приведет к аннулированию кэшированного значения. Однако, если реактивная зависимость делает недействительным кэшированное значение, то любые измененные нереактивные зависимости все равно будут извлечены при вычислении нового значения.
Самый простой способ выяснить, является ли объект / массив реактивным, — это вывести его на консоль. Когда Vue делает объект реактивным, он заменяет все его свойства на геттеры и сеттеры, и это меняет то, как он отображается в консоли.
Обычно vue делает объект реактивным только один раз, когда он впервые добавляется в data
. Только для свойств, существующих в этот момент, будут созданы геттеры и сеттеры, что приводит к общей проблеме, заключающейся в том, что любые новые свойства, добавленные позже, не будут реактивными. Это то, для чего Vue.set
и vm.$set
предназначены:
https://v2.vuejs.org/v2/api/#vm-set
Недавно добавлен Vue Vue.observable
, который позволяет сделать объекты реактивными без прохождения data
: