ViewChild 和 ContentChild 的有效选择器是什么?

2023-12-06

我正在寻找可用于访问子组件/DOM 元素的有效选择器的完整列表@ViewChild and @ContentChild.

说我有孩子HelloComponent:

我知道我可以添加模板#ref并查询它,如下所示:

<hello #myHello></hello>

@ViewChild('myHello') myHello: HelloComponent;

或者我可以直接查找该组件(无需模板#ref):

@ViewChild(HelloComponent) myHello: HelloComponent;

In 这个问题,提到可以使用以下选择器:

我们目前支持 CSS 选择器的子集:
* 元素选择器
* 属性选择器(包括值)
* :not(...) 伪选择器
* 以上的组合(包括,)

但是当我在 Stackblitz 中测试这些来验证时(这是那个的链接),我实际上无法让前三个中的任何一个工作。(检查控制台可以看到undefined对于我无法工作的选择器类型。我不确定我是否对这些选择器做错了什么,或者实际列表是否不同。)

那么,哪些选择器可以工作呢?另外,列表是否相同@ViewChild, @ContentChild, @ViewChildren, and @ContentChildren?


首先,正如 @JB Nizet 在评论中已经提到的该问题中的评论是错的:它与查询选择器无关,而是引用指令选择器.

让我们检查一下可以使用哪种选择器进行查询。

角度文档states对于查询:

selector- 用于查询的指令类型或名称。

指令类型

似乎任何人都应该清楚(1) 我们可以查询由以下修饰的任何类@Component or @Directive装饰者.

@Component({
  selector: 'some-comp',
  template: '...'
})
export class SomeComp {}

@Directive({
  selector: '[someDir]'
})
export class SomeDir {}

@Component({
  selector: 'host-comp',
  template: `
    <some-comp someDir></some-comp>
  `
})
export class HostComp {
  @ViewChild(SomeComp) someComp: SomeComp;
  @ViewChild(SomeDir) someDir: SomeDir;
}

查询时使用的名称

对我来说,这是令人困惑的描述。

原来这里的名字是(2) 姓名模板引用变量这是一个字符串:

@Component({
  selector: 'host-comp',
  template: `
    <some-comp #someComp></some-comp>
  `
})
export class HostComp {
  @ViewChild('someComp') someComp: SomeComp;
}

我们可能会到这里,但现在是时候看一下 Angular 源代码并更深入地研究一下了。

隐藏行为

让我们看看the code角度编译器用来读取查询元数据:

private _queryVarBindings(selector: any): string[] { return selector.split(/\s*,\s*/); }

private _getQueryMetadata(q: Query, propertyName: string, typeOrFunc: Type|Function):
      cpl.CompileQueryMetadata {
  let selectors: cpl.CompileTokenMetadata[];
  if (typeof q.selector === 'string') {
    selectors =
        this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
  } else {
    if (!q.selector) {
      this._reportError(
          syntaxError(
              `Can't construct a query for the property ...`),
          typeOrFunc);
      selectors = [];
    } else {
      selectors = [this._getTokenMetadata(q.selector)];
    }
}

从前面的代码我们可以得出这样的结论:

  • 如果选择器是一个字符串除以,那么我们就可以构造多个选择器。

  • 另一方面,如果选择器不是字符串,那么我们只能得到一个选择器

  • 编译器使用this._getTokenMetadata从传递的选择器中提取信息的方法,但它与用于提取提供者元数据的方法相同https://github.com/angular/angular/blob/4c089c1d931c0ea35591837706de205a75a61ccb/packages/compiler/src/metadata_resolver.ts#L1073-L1077

让我们应用从上面的代码中学到的知识。

We (3) 可以通过使用多个模板引用变量除以来查询多个值,:

@Component({
  selector: 'a',
  template: '...'
})
export class A {}

@Component({
  selector: 'b',
  template: '...'
})
export class B {}

@Component({
  selector: 'host-comp',
  template: `
    <a #a></a>
    <b #b></b>
  `
})
export class HostComp {
  @ViewChildren('a, b') components;

  ngAfterViewInit() {
    console.log(this.components); // [A, B]
  }
}

(4) 可以查询组件或指令上定义的Provider。(另请参阅@Ilia Volk 添加的示例)

@Component({
  selector: 'a',
  template: '...',
  providers: [SomeService]
})
export class A {}

@Component({
  selector: 'host-comp',
  template: `<a></a>`
})
export class HostComp {
  @ViewChild(SomeService) someService: SomeService;
}

由于字符串可以作为提供者的令牌,我们可以(5) 查询通过字符串token定义的几个provider

@Component({
  selector: 'a',
  providers: [{ provide: 'tokenA', useValue: 'TokenAValue' }],
  template: '...'
})
export class A { }

@Component({
  selector: 'b',
  providers: [{ provide: 'tokenB', useValue: 'TokenBValue' }],
  template: '...'
})
export class B { }

@Component({
  selector: 'host-comp',
  template: `
    <a #a></a>
    <b #b></b>
  `
})
export class HostComp {
  @ViewChildren('tokenA, tokenB') stringTokenProviders;

  ngAfterViewInit() {
    console.log(this.stringTokenProviders); // ['TokenAValue', 'TokenBValue']
  }
}

我们的下一站是核心包中的地方Angular 返回特定查询的值:

export function getQueryValue(
    view: ViewData, nodeDef: NodeDef, queryValueType: QueryValueType): any {
  if (queryValueType != null) {
    // a match
    switch (queryValueType) {
      case QueryValueType.RenderElement:
        return asElementData(view, nodeDef.nodeIndex).renderElement;
      case QueryValueType.ElementRef:
        return new ElementRef(asElementData(view, nodeDef.nodeIndex).renderElement);
      case QueryValueType.TemplateRef:
        return asElementData(view, nodeDef.nodeIndex).template;
      case QueryValueType.ViewContainerRef:
        return asElementData(view, nodeDef.nodeIndex).viewContainer;
      case QueryValueType.Provider:
        return asProviderData(view, nodeDef.nodeIndex).instance;
    }
  }
}

RenderElement上面的代码中是一些我们无法查询的内部令牌。

ElementRef可以通过模板引用变量或使用阅读选项

(6)TemplateRef可以通过以下方式查询selector:

@Component({
  selector: 'host-comp',
  template: `
    <ng-template></ng-template>
  `
})
export class HostComp {
  @ViewChild(TemplateRef) template;
}

当然还有ViewContainerRef通过read option.

Provider可以通过使用获得read选项或通过选择器,正如我在这个答案中所描述的那样。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ViewChild 和 ContentChild 的有效选择器是什么? 的相关文章

随机推荐

  • 使用 Maven 构建 Groovy 项目时出现源错误

    我正在尝试使用 maven 构建我的第一个 groovy 项目 但我从 maven 收到以下错误 它是某种类型的源错误 但我不明白为什么我会收到它 INFO BUILD FAILURE INFO INFO Total time 3 186s
  • IntelliJ的Scala增量编译什么时候发生?

    IntelliJ的Scala增量编译什么时候发生 我注意到对文件进行更改不会导致相应的 class 文件 在 target 中 被更新 什么时候会发生这种情况 我认为你误解了 Scala 增量编译的工作原理 有两种不同的东西可以称为 Int
  • 访问VBA:查找列中的最大数字并加1

    在我的 Access 数据库中 我有一个名为 Demande 的表 我想读取 Numero de Commande 列中的所有记录并读取该列中最大的数字 以便我可以将该数字用于下一个新记录 这是我的桌子 关键索引是针对 Numero de
  • Windows Azure 与.NET 2.0 框架兼容吗?

    我有一个在 NET 2 0 框架中开发的服务 它安装在多个站点中并与我的应用程序一起使用 我希望该服务能够向我 报告 有关该应用程序的某些信息 我想看看 Windows Azure 是否可以让我将报告存储在云数据库中 并在需要时提取它们 我
  • 重写 WinForm ListView 控件上的 Drawitem 事件

    我希望 ListView 的所选项目在焦点丢失时保持清晰可见 在 Windows 7 上为暗灰色 我确实将 HideSelection 属性设置为 False 我想对列表视图执行某人对 TreeView 控件所做的操作 即重写 Drawno
  • Kubernetes 中具有子域重定向的通配符 SSL 证书

    我已将 Kubernetes 配置为使用 cert manager 和 LetsEncrypt 对我的所有应用程序使用一个通配符 SSL 证书 现在的问题是我无法配置子域重定向 因为 Ingress 有点 僵硬 以下是我试图实现这一目标的方
  • 将 char 存储到 int 变量中

    我正在学习 C 中的隐式转换 我读了下面的例子 char a std cin gt gt a I can enter an integer like 56 here std cout lt
  • 当我尝试使用最新的依赖项构建 Maven 空手道项目时出现编译错误

    I m new to Karate API automation tool and just try to set up the tool I m getting Compilation errors when I try to compi
  • 使用 setRepeating() 方法了解下一个闹钟时间

    我有时会在上午 9 00 下午 1 00 晚上 7 00 等时间设置 3 个待处理意图 这些意图每天使用 setRepeating 方法递归触发 这里我将所有这些待处理的意图唯一请求代码保存在本地 SQLite 数据库中 在这里 每当触发警
  • FFREE ST(i) 修改 x87 标记字中的哪些位?

    这个例子是用 NASM 编写的 section bss var28 resb 28 section text main Initialize finit fldpi Read Tag Word fstenv var28 mov ax var
  • 闭包中引用的生命周期

    我需要一个闭包来引用其封闭环境中的对象的一部分 该对象是在环境中创建的 并且范围仅限于该环境 但一旦创建 它就可以安全地移动到闭包中 用例是一个函数 它执行一些准备工作并返回一个将完成其余工作的闭包 这种设计的原因是执行限制 第一部分工作涉
  • 向量的数值导数

    我遇到一个向量 x Nx1 相对 于另一个与 x 大小相同的向量 t 时间 的数值导数的问题 我执行以下操作 以 x 被选为正弦函数为例 t t0 ts tf x sin t xd diff x ts 但答案 xd 是 N 1 x1 并且我
  • 删除名称以特定字符串开头的所有表

    如何删除名称以给定字符串开头的所有表 我认为这可以通过一些动态 SQL 来完成INFORMATION SCHEMA tables 如果数据库中有多个所有者 您可能需要修改查询以包含所有者 DECLARE cmd varchar 4000 D
  • 为 WebGL 示例嵌入 ChakraHost (c#)

    我研究了涉及嵌入 javascript 框架 paper js 的示例 用于通过 ChakraHost 的 JsBridge 实现将输出绘制到 XAML 的 CanvasControl 要包含 paper js 框架和调用该框架的 java
  • ValueError: check_hostname 需要使用 Fiddler 4 的 server_hostname

    This question最近刚刚发布的有一些有用的答案 但与我的不一样 我正在从 ArcGIS Pro Notebook 运行 urllib3 1 26 4 和 Python 3 7 我还打开了 Fiddler 4 因为我想在对脚本进行故
  • 当我的编译器不符合标准时如何将数组成员归零

    我的编译器 C Builder6 在语法上允许数组成员初始化 至少为零 但实际上它并没有真正做到这一点 因此 下面给出的示例中的断言会失败 具体取决于上下文 include
  • 导航到新页面并显示警告框

    我正在使用 ASP Net WebForm 开发一个应用程序 一旦用户单击按钮 应用程序将导航到新页面并提示对话框 欢迎来到 JackiesGame 但是 我能够导航到新页面 但不显示警报对话框 以下是我的示例代码 void cmdCanc
  • PHP 中简单干净的 xml 操作

    我正在尝试寻找一种在 php 中轻松修改 xml 的方法 PHP 文档对于如何轻松操作 xml 非常令人困惑 我喜欢 SimpleXml 如何轻松查找标签 属性 但它似乎不允许您轻松添加子树或替换现有的子树 关于使用什么有什么建议吗 我的用
  • 为什么jstl的formatNumber货币符号区域设置在设置currencyCode时是特定的

    我使用 formatNumber 如下
  • ViewChild 和 ContentChild 的有效选择器是什么?

    我正在寻找可用于访问子组件 DOM 元素的有效选择器的完整列表 ViewChild and ContentChild 说我有孩子HelloComponent 我知道我可以添加模板 ref并查询它 如下所示