我正在寻找一个完整的有效选择器列表,我可以通过@ViewChild和来访问子组件/ DOM元素@ContentChild.
说我有一个孩子HelloComponent:
我知道我可以#ref为它添加模板和查询,如下所示:
<hello #myHello></hello>
@ViewChild('myHello') myHello: HelloComponent;
Run Code Online (Sandbox Code Playgroud)
或者我可以直接查找该组件(没有模板#ref):
@ViewChild(HelloComponent) myHello: HelloComponent;
Run Code Online (Sandbox Code Playgroud)
在本期中,提到可以使用以下选择器:
我们目前支持CSS选择器的一个子集:
*元素选择器
*属性选择器(包括值)
*:not(...)伪选择器
*上面的组合(包括,)
但是当我在Stackblitz中测试这些以验证时(这是它的链接),我实际上无法让前三个中的任何一个工作.(检查控制台以查看undefined我无法工作的选择器类型.我不确定这些选择器是否出错或者实际列表是否不同.)
那么,哪些选择器会起作用?此外,在名单同样为@ViewChild,@ContentChild,@ViewChildren,和@ContentChildren?
yur*_*zui 59
首先,正如@JB Nizet在评论中已经提到的那样,问题中的评论是错误的:它与查询选择器无关,而是指向指令选择器.
让我们来看看我们可以用于查询的选择器类型.
Angular文档声明对于查询:
selector - 用于查询的指令类型或名称.
看来,这应该是清楚的人是(1),我们可以通过查询任何装饰类@Component或@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;
}
Run Code Online (Sandbox Code Playgroud)
至于我,这是令人困惑的描述.
事实证明,这里的名称是(2)模板引用变量的名称,它是一个字符串:
@Component({
selector: 'host-comp',
template: `
<some-comp #someComp></some-comp>
`
})
export class HostComp {
@ViewChild('someComp') someComp: SomeComp;
}
Run Code Online (Sandbox Code Playgroud)
我们可以在这里结束,但现在是时候看看角度源代码并深入了解一下.
让我们看看角度编译器用于读取查询元数据的代码:
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)];
}
}
Run Code Online (Sandbox Code Playgroud)
从前面的代码我们可以得出结论:
如果selector是一个字符串除以,那么我们可以构造多个选择器.
另一方面,如果selector不是字符串,那么我们只能获得一个选择器
编译器使用this._getTokenMetadata方法从传递的选择器中提取信息,但它与用于提取提供程序元数据的方法相同https://github.com/angular/angular/blob/4c089c1d931c0ea35591837706de205a75a61ccb/packages/compiler/src/metadata_resolver.ts#L1073-L1077
让我们从上面的代码中学习我们的知识.
我们(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]
}
}
Run Code Online (Sandbox Code Playgroud)
(4)可以查询在组件或指令上定义的提供者.(另见@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;
}
Run Code Online (Sandbox Code Playgroud)
由于字符串可以是提供者的标记,因此我们可以(5)查询通过字符串标记定义的多个提供者
@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']
}
}
Run Code Online (Sandbox Code Playgroud)
接下来我们的停靠点是核心包中的位置,其中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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
RenderElement 在上面的代码中是一些我们无法查询的内部令牌.
ElementRef可以通过模板引用变量或使用read选项查询
(6)可以通过selector以下方式查询TemplateRef:
@Component({
selector: 'host-comp',
template: `
<ng-template></ng-template>
`
})
export class HostComp {
@ViewChild(TemplateRef) template;
}
Run Code Online (Sandbox Code Playgroud)
当然还有ViewContainerRef通过read选项.
Provider可以通过使用read选项或通过选择器获得,如我在本答案中间所述.
| 归档时间: |
|
| 查看次数: |
12935 次 |
| 最近记录: |