如何在 Angular 6 中选择原生元素的 ContentChild?

Yul*_*ian 6 angular-template angular-directive angular angular6

我有一个使用内容投影的组件。

<ng-content select="button">
</ng-content>
Run Code Online (Sandbox Code Playgroud)

我想在我的组件中做这样的事情:

@ContentChild('button') button: ElementRef;
Run Code Online (Sandbox Code Playgroud)

但是,当我检查时this.button,它undefined同时在ngAfterViewInit和 中ngAfterContentInit

如果我的内容子元素是原生元素而不是自定义组件,我该如何选择它?

Cob*_*ger 8

要理解的重要事情是,你传递给选择@ContentChild不是一个CSS选择器,你无法找到基于其ID,类或元素类型内容的孩子。您只能搜索使用#运算符提供的标识符名称。

所以给定一个组件调用my-comp和以下用法:

<my-comp><button #buttonName>Click me</button></my_comp>
Run Code Online (Sandbox Code Playgroud)

您可以使用以下方法找到它:

@ContentChild('buttonName') button: ElementRef;
Run Code Online (Sandbox Code Playgroud)

编辑

正如 OP 对 ckTag 答案的评论中所指出的(他比我领先一分钟),这确实意味着调用代码需要知道您希望内容被标记为特定名称。

如果您的组件确实需要了解其子内容的详细信息,则更好的答案实际上是将指令类型提供给@ContentChild

@ContentChild(MyButtonComponent, { read: ElementRef })
button: ElementRef;
Run Code Online (Sandbox Code Playgroud)

这也更好,因为您现在可以实际期望知道内容的类型;调用代码可以坚持#buttondiv,如果感觉吧,毕竟。

这确实意味着告别使用常规 HTMLbutton元素,但还有其他好处。例如,您可以提供一条消息来指导您的调用代码,如下所示:

<ng-content></ng-content>
<div *ngIf="button">Error: Please provide a MyButtonComponent</div>
Run Code Online (Sandbox Code Playgroud)

  • @CobusKruger 实际上,如果您有 &lt;ng-content select="button"&gt;&lt;/ng-content&gt;,调用代码不应该允许除本机按钮元素之外的任何其他内容,是吗? (2认同)

Rea*_*lar 7

没有一个查询装饰器可以在没有引用的情况下选择本机元素。

@ViewChild('button')
@ViewChildren('button')
@ContentChild('button')
@ContentChildren('button')
Run Code Online (Sandbox Code Playgroud)

它不是 CSS 选择器。

查询装饰器在依赖图中搜索匹配类型并选择它们。匹配类型可以是模板引用、组件或指令。

在内容中选择特定元素的推荐方法是用指令标记它。

@Directive({...})
export class MyButtonDirective {}
Run Code Online (Sandbox Code Playgroud)

现在您可以在您的父组件中查询它。

@ContentChild(MyButtonDirective) button: MyButtonDirective;
Run Code Online (Sandbox Code Playgroud)

当您使用字符串值时,它指的是模板变量引用。这些被写成#someValue,它们可以是模板引用、组件或指令。

<button #myButton></button>
Run Code Online (Sandbox Code Playgroud)

您现在可以将上述内容引用为

@ViewChild('myButton')
Run Code Online (Sandbox Code Playgroud)

ContentChild由于视图的工作方式,我不知道这是否适用。一个#myButton模板变量可能不是在父母的依赖关系图中可见。

或者,您可以注入ElementRef父组件的 ,然后使用本机 JavaScript 搜索您正在寻找的子组件。从 Angular 的角度来看,这是一种不好的做法,因为其想法是将您的应用程序与 DOM 分开。