Angular 5:从投影子组件中获取父组件的ViewContainerRef
在Angular 5里,投影子组件的注入上下文是声明它的组件(比如你的App组件),而不是它被投影到的父组件,所以直接依赖注入ParentComponent会找不到实例。不过有几种可靠的方法能实现你的需求:
方法1:父组件主动传递ViewContainerRef给投影子组件
这是最稳妥、符合Angular设计理念的方式。父组件可以通过@ContentChildren获取所有投影进来的子组件,然后把自己的ViewContainerRef主动传递过去:
步骤1:修改父组件
在父组件中注入自身的ViewContainerRef,然后通过@ContentChildren捕获投影的子组件,在ngAfterContentInit生命周期钩子中完成传递:
import { Component, ViewContainerRef, ContentChildren, QueryList, AfterContentInit } from '@angular/core'; import { ChildComponent } from './child.component'; @Component({ selector: 'parent', template: ` <ng-container #container></ng-container> <ng-content></ng-content> ` }) export class ParentComponent implements AfterContentInit { @ContentChildren(ChildComponent) childComponents: QueryList<ChildComponent>; // 注入父组件自身的ViewContainerRef constructor(public viewContainerRef: ViewContainerRef) {} ngAfterContentInit() { // 遍历所有投影子组件,传递父组件的ViewContainerRef this.childComponents.forEach(child => { child.setParentVcr(this.viewContainerRef); }); } }
步骤2:修改子组件
在子组件中添加一个方法,接收父组件传递过来的ViewContainerRef:
import { Component, ViewContainerRef } from '@angular/core'; @Component({ selector: 'child', template: `<!-- 子组件内容 -->` }) export class ChildComponent { private parentVcr: ViewContainerRef; setParentVcr(vcr: ViewContainerRef) { this.parentVcr = vcr; // 现在你就可以用这个父组件的ViewContainerRef做任何操作了,比如动态创建组件 } }
方法2:子组件通过DOM遍历+Injector查找父组件实例
这种方法不需要父组件做太多修改,但依赖DOM结构,适合简单场景:
在子组件中,通过ElementRef向上遍历DOM树,结合Injector查找父组件的实例,进而获取它的ViewContainerRef:
import { Component, ElementRef, Injector, OnInit } from '@angular/core'; import { ParentComponent } from './parent.component'; @Component({ selector: 'child', template: `<!-- 子组件内容 -->` }) export class ChildComponent implements OnInit { private parentVcr: ViewContainerRef; constructor(private elRef: ElementRef, private injector: Injector) {} ngOnInit() { let currentEl = this.elRef.nativeElement.parentElement; // 向上遍历DOM树,查找父组件实例 while (currentEl) { try { const parentComponent = this.injector.get(ParentComponent, null, { host: currentEl }); if (parentComponent) { this.parentVcr = parentComponent.viewContainerRef; break; } } catch (e) { // 找不到对应组件,继续向上遍历 } currentEl = currentEl.parentElement; } } }
额外说明
如果你需要的是父组件中那个#container的ViewContainerRef(而非父组件自身的),只需要把父组件中的constructor(public viewContainerRef: ViewContainerRef)改成@ViewChild('container') public viewContainerRef: ViewContainerRef;即可。
内容的提问来源于stack exchange,提问作者user636525
相关产品推荐
相关产品推荐

