Шаблоны $parent и $children

В Части 1 этой серии мы представили два шаблона, которые отлично работают в двухуровневой иерархии компонентов, но как насчет трехуровневой, или даже четырех-, или пятиуровневой иерархии? Теперь, следуя начальным примерам Части 1, добавим новый компонент GrandchildA, и вот начальное состояние трех компонентов:

Parent имеет компонент ChildA, который получает событие input, привязанное к его тегу. Это паттерн пользовательская v-модель, обсуждавшийся в Части 1.

Подобно Parent, ChildA теперь имеет компонент GrandchildA, который получает событие input, привязанное к его тегу, и передает данные desserts, полученные от Parent, в GrandchildA. Обратите внимание на функцию наблюдения за реквизитом value в строке 38, это делается для того, чтобы каждый раз при изменении реквизита ChildA.desserts получало самое последнее значение.

Кроме того, GrandchildA передаст свои данные ChildA, а ChildA передаст их обратно Parent, как показано в строках 43–46.

GrandchildA имеет те же настройки, что и ChildA в Части 1, у него есть кнопка, куда мы можем добавить новый десерт. В функции обработчика событий handleUpdate он будет использовать $emit для запуска события input, связанного с ним в ChildA, и передавать новые данные в качестве аргумента.

Вот текущий вид:

Теперь, если пользователь нажмет кнопку Update на GrandchildA, представление станет таким:

GrandchildA отправляет обновленный desserts ChildA с помощью this.$emit('input', this.desserts), а ChildA делает то же самое и передает данные Parent, Parent обновляет свой this.desserts, используя новое значение, и передает его ChildA в качестве опоры. ChildA наблюдает за изменением значения реквизита, поэтому он обновит свой this.desserts, а this.desserts будет передан GrandchildA в качестве реквизита.

Таким образом, чтобы GrandchildA мог общаться с Parent, он должен пройти через посредника ChildA. Как насчет добавления компонента GrandGrandchild? Он будет следовать тому же подходу, и ChildA и GrandchildA станут посредниками. Когда дело доходит до многоуровневой иерархии, мы можем повторить два шаблона из Части 1 в каждом компоненте-потомке, но есть способ получше.

$родительский шаблон

Теперь давайте изменим GrandchildA.handleUpdate():

Благодаря изысканному дизайну Vue нам на самом деле не нужно запускать событие input в GrandchildA, а затем выполнять функцию обратного вызова в ChildA. Вместо этого в GrandchildA мы можем напрямую инициировать событие input в ChildA, используя this.$parent для выполнения функции обратного вызова в Parent, потому что GrandchildA.$parent = ChildA. Супер просто, не так ли?

Поскольку нам больше не нужен ChildA для выполнения работы посредника, теперь ChildA может быть очень простым:

ChildA становится только получать реквизит и передавать его GrandchildA. Если мы сейчас нажмем кнопку Update, она будет работать так же:

Новые данные desserts обновляются из GrandchildA непосредственно в Parent, а затем передаются в ChildA и GrandchildA.

$детский шаблон

В дереве компонентов Vue есть $parent и, конечно же, $children. Давайте посмотрим на пример $children. GrandchildA оставим как есть, а в ChildA теперь привязываем новое событие с именем show:alert на тег GrandchildA:

И функция обратного вызова события — handleShowAlert, которая покажет предупреждение. Теперь в Parent добавим новую кнопку:

При нажатии кнопки мы хотим инициировать событие show:alert для GrandchildA, которое, в свою очередь, выполнит ChildA.handleShowAlert() для отображения предупреждения. Это достигается с помощью:

this.$children[0].$children[0].$emit('show:alert');

Поскольку $children — это массив экземпляров VueComponent и для Parent и ChildA есть только один дочерний элемент, мы можем использовать $children[0]. Теперь, если пользователь нажмет кнопку:

Предупреждение отображается, как и ожидалось.

Заключение

Для многоуровневой иерархии компонентов подходят шаблоны «$parent и $children», поскольку они могут уменьшить поуровневую передачу данных между компонентами. Но если уровней слишком много, то нам придется сделать что-то вроде этого:

this.$parent.$parent.$parent.$parent.$emit('input', this.desserts);

Кроме того, у родительского компонента может быть много дочерних компонентов, а у каждого дочернего компонента может быть множество дочерних компонентов. Как определить конкретный дочерний компонент в массиве $children? Этот вопрос приведет нас к части 3 этой серии, где мы постараемся его решить.

Вот все статьи из этой серии:

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 1

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 2

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 3

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 4

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 5

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 6

Шаблоны взаимодействия компонентов Vue.js (без Vuex) — часть 7