В чем разница между @ViewChild и @ContentChild?

189

Угловая 2 предусматривает @ViewChild, @ViewChildren, @ContentChildи @ContentChildrenдекоратор для запроса потомков элементов отображения компонента.

В чем разница между первыми двумя и двумя последними?

Дрю Мур
источник
3
Эта ссылка помогла мне blog.mgechev.com/2016/01/23/… после прочтения ответов ниже. Приветствия :)
Гопинатх Шива

Ответы:

256

Я отвечу на ваш вопрос, используя терминологию Shadow DOM и Light DOM (это пришло из веб-компонентов, подробнее здесь ). В основном:

  • Shadow DOM - это внутренний DOM вашего компонента, который определяется вами (как создателем компонента ) и скрыт от конечного пользователя. Например:
@Component({
  selector: 'some-component',
  template: `
    <h1>I am Shadow DOM!</h1>
    <h2>Nice to meet you :)</h2>
    <ng-content></ng-content>
  `;
})
class SomeComponent { /* ... */ }
  • Light DOM - это DOM, который конечный пользователь вашего компонента поставляет в ваш компонент. Например:
@Component({
  selector: 'another-component',
  directives: [SomeComponent],
  template: `
    <some-component>
      <h1>Hi! I am Light DOM!</h1>
      <h2>So happy to see you!</h2>
    </some-component>
  `
})
class AnotherComponent { /* ... */ }

Итак, ответ на ваш вопрос довольно прост:

Разница между @ViewChildrenи @ContentChildrenзаключается в том, что @ViewChildrenищите элементы в Shadow DOM, а @ContentChildrenищите их в Light DOM.

alexpods
источник
10
Запись в блоге blog.mgechev.com/2016/01/23/… от Минько Гечу имеет для меня больше смысла. @ContentChildren - это дочерние элементы, вставляемые проекцией содержимого (дочерние элементы между <ng-content> </ ng-content>). Из блога Minkos: «С другой стороны, ** элементы, которые используются между открывающим и закрывающим тегами хост-элемента данного компонента, называются * content children **." Shadow DOM и представление инкапсуляции в Angular2 описаны здесь: blog.thoughtram.io/angular/2015/06/29/… .
Уэстор
4
Для меня это звучит так, как будто @TemplateChildren(вместо @ViewChildren) или @HostChildren(вместо @ContentChildren) были бы гораздо более подходящие имена, поскольку в таком контексте все, о чем мы говорим, связано с представлением, а также с привязкой к содержимому.
Superjos
35
@ViewChildren== ваш собственный ребенок; @ContentChildren== чей-то еще ребенок
candidJ
107

Как следует из названия, @ContentChildи @ContentChildrenзапросы будут возвращать директивы, существующие внутри <ng-content></ng-content>элемента вашего представления, тогда как @ViewChildи @ViewChildrenсмотреть только на элементы, которые находятся в вашем шаблоне представления напрямую.

Дрю Мур
источник
Так что используйте @ViewChild (ren), если у вас нет компонентов в вашем представлении, в каком случае используйте @ContentChild (ren)?
Бен Талиадорос
31

Это видео от Angular Connect содержит отличную информацию о ViewChildren, ViewChild, ContentChildren и ContentChild https://youtu.be/4YmnbGoh49U

@Component({
  template: `
    <my-widget>
      <comp-a/>
    </my-widget>
`
})
class App {}

@Component({
  selector: 'my-widget',
  template: `<comp-b/>`
})
class MyWidget {}

С my-widgetточки зрения, comp-aэто ContentChildи comp-bесть ViewChild. CompomentChildrenи ViewChildrenвернуть итерируемое, в то время как xChild возвращает один экземпляр.

mithun_daa
источник
Это лучшее объяснение. Спасибо :)
Джавид
Вы сделали простой и понятный пример, но шаблон MyWidget должен быть <comp-b><ng-content></ng-content></comp-b>правильным?
Арджел
1

Давайте рассмотрим пример. У нас есть один домашний компонент и один дочерний компонент, а внутри дочернего компонента - один маленький дочерний компонент.

<home>
     <child>
           <small-child><small-child>
     </child>
</home>

Теперь вы можете захватить все дочерние элементы в контексте домашнего компонента с помощью @viewChildren, потому что они непосредственно добавляются в шаблон домашнего компонента. Но когда вы пытаетесь получить доступ к <small-child>элементу из контекста дочернего компонента, вы не можете получить к нему доступ, потому что он не добавляется непосредственно в шаблон дочернего компонента. Он добавляется через проекцию контента в дочерний компонент домашним компонентом. Вот где приходит @contentChild, и вы можете получить его с помощью @contentChild.

Разница возникает при попытке доступа к элементам ссылки в контроллере. Вы можете получить доступ ко всем элементам, которые непосредственно добавляются в шаблон компонента с помощью @viewChild. Но вы не можете получить ссылку на проецируемые элементы с помощью @viewChild. Для доступа к проецируемому элементу вы должны использовать @contentChild.

Dev Verma
источник