关于|关于 Angular view Query 的 id 选择器问题的单步调试

问题描述 【关于|关于 Angular view Query 的 id 选择器问题的单步调试】我有这样一个 Angular Component,模板文件如下:
@Component({
selector: 'example-app',
template: `

1 2 Selected: {{selectedPane}}

`,
})
在其 Component 实现里,我期望通过 `@ViewChild`,在运行时拿到 id 为 `panel 1?` 的 div 元素的实例。

export class ViewChildComp {
constructor(public changeDetectorRef: ChangeDetectorRef
){}

@ViewChild("panel 1?")
set panethis(v) {
//setTimeout(()=> this.selectedPane = v.id, 0); this.selectedPane = v.id; this.changeDetectorRef.detectChanges(); //Promise.resolve().then(() => this.selectedPane = v.id);

}
然而运行时没有得到期望的结果,报错:> ERROR TypeError: Cannot read properties of undefined (reading 'id') at ViewChildComp.set (ng-content.component.ts:57:27) at ViewChildComp_Query (template.html:3:5) at executeViewQueryFn (core.js:8758:5) at refreshView (core.js:7437:13) at refreshComponent (core.js:8527:13) at refreshChildComponents (core.js:7186:9) at refreshView (core.js:7430:13) at refreshComponent (core.js:8527:13) at refreshChildComponents (core.js:7186:9) at refreshView (core.js:7430:13)![](https://img-blog.csdnimg.cn/img_convert/1d29328a6be49ed1e119745caefa63b1.png)# 问题分析我们点击上图高亮的 `template.html` 调用栈:来到我们自己 Component 的模板文件,因为这是一个内联到 Component 里的模板,所以显示为 `template.html` :![](https://img-blog.csdnimg.cn/img_convert/2140eff3d8570bd0f22607150cef7b20.png)通过单步调试,能发现在 `refreshView` 里,执行 `view query` 的入口逻辑:![](https://img-blog.csdnimg.cn/img_convert/df617666099340eab55838e58cd5024e.png)

function executeViewQueryFn(flags, viewQueryFn, component) {
ngDevMode && assertDefined(viewQueryFn, 'View queries function to execute must be defined.'); setCurrentQueryIndex(0); viewQueryFn(flags, component);

}
![](https://img-blog.csdnimg.cn/img_convert/304d594c84cfd4e2af5c0c95c43270fc.png)根据关键字 `view query` 查询 Angular 官网,发现在 view query 里使用 id 选择器的正确语法,并不是直接查询 HTML 元素的 id 属性,而是需要在 HTML 元素或者 `ng-template` 里使用符号 `#` 指定一个 id,然后将这个 id 传入 `@ViewChild`:![](https://img-blog.csdnimg.cn/img_convert/14ecb16c8af684711c957e70f9680995.png)![](https://img-blog.csdnimg.cn/img_convert/12cf2562baa0833a139a44357bed480a.png)修改之后的运行效果: ![](https://img-blog.csdnimg.cn/img_convert/f2b7c1b02f4381e00dc5908a9c1effac.png)# 总结view query 在父 Component 需要访问其子 Component 的场景下特别有用。假设有一个 alert Component:

@Component({
selector: 'alert',
template: `
{{type}}

`,
})
export class AlertComponent {
@Input() type: string = "success";
alert() {
console.log("alert");

}
}
在我们的父 Component 里,可以定义 AlertComponent 的多个实例:

@Component({
selector: 'my-app',
template: `

`,
})
export class App {
@ViewChildren(AlertComponent) alerts: QueryList
ngAfterViewInit() {
this.alerts.forEach(alertInstance => console.log(alertInstance));

}
}
我们可以使用 @ViewChildren 装饰器从宿主视图中抓取元素。 @ViewChildren 装饰器支持指令或组件类型作为参数,或模板变量的名称。 当参数是组件/指令时,返回值将是组件/指令实例。上面例子的 console.log 语句会打印 AlertComponent 的实例: ![](https://img-blog.csdnimg.cn/img_convert/cbc8a51a3073e5da4c11f58b960c6326.png)

    推荐阅读