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

Posted

技术标签:

【中文标题】如何在 Angular 6 中选择原生元素的 ContentChild?【英文标题】:How do I select a ContentChild of a native element in Angular 6? 【发布时间】:2019-01-11 10:14:56 【问题描述】:

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

<ng-content select="button">
</ng-content>

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

@ContentChild('button') button: ElementRef;

但是,当我检查this.button 时,undefinedngAfterViewInitngAfterContentInit 中都是ngAfterContentInit

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

【问题讨论】:

【参考方案1】:

要了解的重要一点是,您传递给@ContentChild 的选择器不是 CSS 选择器,您无法根据其ID、类或元素类型找到内容子项。您只能使用 # 运算符搜索您为其提供的标识符名称。

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

<my-comp><button #buttonName>Click me</button></my_comp>

您可以通过以下方式找到它:

@ContentChild('buttonName') button: ElementRef;

编辑

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

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

@ContentChild(MyButtonComponent,  read: ElementRef )
button: ElementRef;

这也更好,因为您现在可以实际期望知道内容的类型;毕竟,调用代码可以将#button 粘贴在div 上。

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

<ng-content></ng-content>
<div *ngIf="button">Error: Please provide a MyButtonComponent</div>

【讨论】:

@CobusKruger 实际上,调用代码不应允许除本机按钮元素之外的任何其他内容,如果您有 ,应该这样吗? @Yulian 我想念你使用了select。我仍然通常将它与我自己的指令一起使用,这意味着调用代码不需要知道“使用此模板引用名称作为按钮”之类的东西。因此,从技术上讲,要求具有给定名称的模板引用变量可能是您要求的答案,但正如您所建议的那样:这是不直观的。【参考方案2】:

没有一个查询装饰器可以选择没有引用的原生元素。

@ViewChild('button')
@ViewChildren('button')
@ContentChild('button')
@ContentChildren('button')

它不是 CSS 选择器。

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

在内容中选择特定元素的推荐方法是使用指令对其进行标记。

@Directive(...)
export class MyButtonDirective 

现在你可以在你的父组件中查询这个了。

@ContentChild(MyButtonDirective) button: MyButtonDirective;

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

<button #myButton></button>

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

@ViewChild('myButton')

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

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

【讨论】:

我正要发布一个带有模板引用变量的答案,如果您在ngAfterContentInit 中访问它,我可以确认它适用于@ContentChild。见this stackblitz。 @ConnorsFan 酷。这不是我通常会做的事情。如果我在模板中看到#myButton 并且我没有看到它在该模板中的任何地方使用,那么我可能会删除它。所以你应该将它们命名为#myButtonForParent @ConnorsFan 很酷,它确实有效,但这意味着 AppComponent 应该知道它应该使用具有 myButton 特定模板引用的按钮。这是它不应该意识到的事情。你不觉得吗? @Yulian 我创建了通用按钮指令,其中只有button 作为它们的选择器。然后,您可以查询那些和其他组件不知道它正在发生。你只需要小心没有其他人使用相同的选择器。

以上是关于如何在 Angular 6 中选择原生元素的 ContentChild?的主要内容,如果未能解决你的问题,请参考以下文章

根据Angular 6中的类删除元素

下面的代码在 Angular 8 中运行。但我需要在 Angular 6 中执行它。我该如何实现呢?

Angular 6 如何在指令中添加多种样式?样式元素未与指令 (addClass) 连接

如何在具有 null 值的 Angular 选择元素上使用默认的“请选择”选项进行验证?

如何通过选择器访问 DOM 元素

当我将元素设置为 Angular 6 中可编辑的内容时,如何设置元素的焦点?