Angular 9中从子组件访问父组件?ViewContainerRef失效问题求助
首先要明确:你之前依赖的this.viewContainerRef['_data'].componentView.component.viewContainerRef['_view'].component是直接访问Angular的私有内部属性,这类属性(以下划线_开头)属于框架内部实现,Angular官方不会保证跨版本的兼容性——这就是为什么Angular 8.2能用,升级到9就失效的核心原因。
下面给你几个官方推荐的、稳定可靠的解决方案:
1. 构造函数直接注入父组件实例(最推荐)
如果你的子组件是父组件的直接子节点,直接在子组件的构造函数中注入父组件类即可:
import { Component } from '@angular/core'; import { ParentComponent } from '../parent/parent.component'; @Component({ selector: 'app-child', template: '<p>Child Component</p>' }) export class ChildComponent { constructor(private parentComponent: ParentComponent) { // 这里直接可以使用parentComponent的属性和方法 console.log(parentComponent.someParentProperty); } }
这种方式是Angular官方设计的组件通信方式,完全符合框架规范,版本升级也不会出问题。
2. 通过@Input传递父组件引用
如果不想让子组件直接依赖父组件类(降低耦合度),可以在父组件模板中将自身作为@Input传递给子组件:
父组件模板
<app-child [parentInstance]="this"></app-child>
子组件代码
import { Component, Input } from '@angular/core'; import { ParentComponent } from '../parent/parent.component'; @Component({ selector: 'app-child', template: '<p>Child Component</p>' }) export class ChildComponent { @Input() parentInstance: ParentComponent; ngOnInit() { console.log(this.parentInstance.someParentProperty); } }
3. 通过Injector获取父组件实例
如果需要通过视图容器相关的方式获取,可以利用Injector(ViewContainerRef也自带injector属性)来获取父组件的注入实例,注意要在视图初始化完成后调用(比如ngAfterViewInit钩子):
import { Component, ViewContainerRef, Injector, AfterViewInit } from '@angular/core'; import { ParentComponent } from '../parent/parent.component'; @Component({ selector: 'app-child', template: '<p>Child Component</p>' }) export class ChildComponent implements AfterViewInit { constructor(private viewContainerRef: ViewContainerRef, private injector: Injector) { } ngAfterViewInit() { // 方式1:用ViewContainerRef的injector const parentComp1 = this.viewContainerRef.injector.get(ParentComponent); // 方式2:直接用注入的Injector const parentComp2 = this.injector.get(ParentComponent); console.log(parentComp1.someParentProperty); } }
为什么viewContainerRef.get(0)返回null?
get(0)是用来获取ViewContainerRef中嵌入的视图的,如果你没有通过createComponent或createEmbeddedView在这个容器中创建视图,它自然会返回null。它的作用不是获取父组件,而是操作当前容器内的视图。
最后再强调一次:永远不要依赖Angular的私有内部属性,这类属性随时可能在版本更新中被修改或移除,导致代码崩溃。优先使用官方提供的API和规范方式实现组件通信。
内容的提问来源于stack exchange,提问作者afeef

