@ViewChild 和 @ContentChild 有啥区别?

Posted

技术标签:

【中文标题】@ViewChild 和 @ContentChild 有啥区别?【英文标题】:What's the difference between @ViewChild and @ContentChild?@ViewChild 和 @ContentChild 有什么区别? 【发布时间】:2016-03-23 11:00:07 【问题描述】:

Angular 2 提供了@ViewChild@ViewChildren@ContentChild@ContentChildren 装饰器,用于查询组件的后代元素。

前两者和后两者有什么区别?

【问题讨论】:

此链接在阅读以下答案后帮助了我blog.mgechev.com/2016/01/23/…。干杯:) 【参考方案1】:

我将使用 Shadow DOMLight DOM 术语来回答您的问题(它来自 Web 组件,请参阅更多 here)。一般来说:

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 中查找它们。

【讨论】:

Minko Gechew 的博客条目blog.mgechev.com/2016/01/23/… 对我来说更有意义。 @ContentChildren 是孩子,由内容投影插入( 之间的孩子)。来自 Minkos 博客:“另一方面,在给定组件的宿主元素的开始标签和结束标签之间使用的 ** 元素称为 *content children **。” Angular2 中的 Shadow DOM 和视图封装在此处描述:blog.thoughtram.io/angular/2015/06/29/…。 对我来说,听起来像@TemplateChildren(而不是@ViewChildren)或@HostChildren(而不是@ContentChildren)会更好的名字,因为在这种情况下,我们的一切谈论是与视图相关的,并且wrt绑定也与内容相关。 @ViewChildren == 你自己的孩子; @ContentChildren == 别人的孩子 @candidJ 今天这是 False,在 ContentChildren 中你有一个默认为 descendants: false 的标志。所以等价是不正确的。 @ViewChild@ContentChild 怎么样?【参考方案2】:

顾名思义,@ContentChild@ContentChildren 查询将返回存在于视图的 &lt;ng-content&gt;&lt;/ng-content&gt; 元素中的指令,而 @ViewChild@ViewChildren 仅直接查看视图模板上的元素。

【讨论】:

所以使用@ViewChild(ren) 除非您的视图中有组件,在这种情况下回退到@ContentChild(ren)?【参考方案3】:

来自 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-aContentChildcomp-bViewChildCompomentChildrenViewChildren 返回一个可迭代对象,而 xChild 返回一个实例。

【讨论】:

这是更好的解释。谢谢:) 你做了一个简单明了的例子,但是MyWidget的模板应该是&lt;comp-b&gt;&lt;ng-content&gt;&lt;/ng-content&gt;&lt;/comp-b&gt;吧?【参考方案4】:

举个例子,我们有一个主组件和一个子组件,在子组件内部有一个小的子组件。

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

现在您可以使用 @viewChildren 获取 home 组件上下文中的所有子元素,因为这些子元素直接添加到 home 组件的模板中。 但是,当您尝试从子组件的上下文中访问 &lt;small-child&gt; 元素时,您将无法访问它,因为它不是直接添加到子组件模板中的。 它是由 home 组件通过内容投影添加到子组件中的。 这就是@contentChild 的用武之地,您可以使用@contentChild 获取它。

当您尝试访问控制器中的元素引用时会发生差异。 您可以访问通过@viewChild 直接添加到组件模板中的所有元素。 但是您无法使用 @viewChild 获取投影元素参考 要访问投影元素,您必须使用 @contentChild。

【讨论】:

【参考方案5】:

只需将 ViewChildren 重命名为 InternalChildren,将 ContentChildren 重命名为 ExternalChildren

【讨论】:

以上是关于@ViewChild 和 @ContentChild 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

可以将@ViewChild 标记为私有吗?

Angular: 属性装饰器ViewChild终章

带有 viewchild 和指令的 Angular 组件测试

Angular 2 @ViewChild 返回未定义

ViewChild 如何在 Angular 和 Storybook 中工作?

Angular @ViewChild() 错误:预期 2 个参数,但得到 1 个