首先,正如 @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
选项或通过选择器,正如我在这个答案中所描述的那样。