이전에 네이티브 API의 동적 뷰 삽입을 소개한 적이 있는데, 이 기능은 이미 대부분의 사용 시나리오를 충족할 수 있습니다. 하지만 아직 Angular 애플리케이션 외부에 콘텐츠를 삽입해야 하는 필요성이 해결되지 않았으며 명령이 동적으로 삽입된 구성 요소와 입력 및 출력 상호 작용을 할 수 없습니다.
다행히 Angular는 동적 뷰 생성을 지원하는 "포털"을 포함한 다양한 Angular 구성 요소 개발을 위한 기본 도구로 구성 요소 개발 키트 세트인 CDK(Component Dev Kit)를 공식적으로 제공합니다.
이 "동적 보기"는 각각 세 가지 포털 유형(ComponentPortal, TemplatePortal, DomPortal)에 해당하는 구성 요소, TemplateRef 또는 DOM 요소일 수 있습니다. 그 중 세 가지의 추상 일반 기본 클래스는 Portal<t></t>
이며, 여기에는 세 가지 메서드가 있습니다: attachment(컨테이너에 마운트), detach(컨테이너에서 제거), isAttached(뷰 여부 결정) 마운트된 상태입니다.) Portal<T>
,有三个方法:attach(挂载到容器)、detach(从容器移除)、isAttached(判断视图是否是挂载状态)。
而容器也是由一个抽象类 BasePortalOutlet
定义,和视图类似,包含 attach(给容器挂载视图)、detach(从容器移除视图)、dispose(销毁容器)、isAttached(是否有挂载视图)。它的主要实现是 DomPortalOutlet
类。用以挂载三种类型的动态视图。
先来看看三种动态视图的创建。
ComponentPortal
相比原生 API,要创建一个动态组件非常的简单,只需要把组件类传入 ComponentPortal
构造函数即可。
this.componentPortal = new ComponentPortal(ExampleComponent);
可以传入任意自定义的组件类,用以创建 ComponentPortal
对象,再动态插入视图中。
✨注意:Angular 9 后的版本推荐使用 Ivy 编译器,如果是老版本编译器,传入的组件类,需要在 Module 的 entryComponents
中声明,并且这个 Module 不能懒加载。
TemplatePortal
TemplatePortal 的构建,相比组件,多了一个参数(ViewContainerRef)。看过前一篇应该对它非常熟悉了,需要依赖它调用 createEmbeddedView()
来创建嵌入视图。这里通过构造注入,直接使用当前组件的 ViewContainerRef
实例。
<ng-template #testTemplate> <p>一些需要动态插入的内容.</p> </ng-template>
@ViewChild('testTemplate') templatePortalContent: TemplateRef<any>; constructor(private _viewContainerRef: ViewContainerRef) { } ngAfterViewInit() { this.templatePortal = new TemplatePortal( this.templatePortalContent, this._viewContainerRef ); }
除了通过构造函数,TemplatePortal 也有一个指令(CdkPortal)可以便捷创建。
<ng-template cdkPortal> <p>一些需要动态插入的内容.</p> </ng-template> <!-- 或写作 --> <!-- 和上面写法是一致的效果 --> <p *cdkPortal> 一些需要动态插入的内容. </p>
然后通过 @ViewChild
就可以获得 TemplatePortal
的实例了。
DomPortal
就像上面的示例通过 @ViewChild
获取 Template 实例来创建,类似的也可以获取 ElementRef 来创建动态的 DOM。
<div #domPortalContent><span>原生DOM内容</span></div>
@ViewChild('domPortalContent') domPortalContent: ElementRef<HTMLElement>; ngAfterViewInit() { this.domPortal = new DomPortal(this.domPortalContent); }
可以动态的将这段 DOM 转移到任意位置。要注意的是,转移之后,原来的数据绑定,或者绑定的指令可能不会再继续更新。
前面三种类型的 Portal 都说了可以渲染到任意位置,那具体怎么渲染呢?
CdkPortOutlet
最简单的就是通过 CdkPortOutlet 指令了:
<div> <ng-template [cdkPortalOutlet]="anyPortal"></ng-template> </div>
给 anyPortal
传值上面三个中任意的 Portal 实例,都会动态渲染到当前位置。
和原生 API 的指令不同,它可以自动判断是什么类型的 Portal。另外,它还有个额外的事件:attached
,通过这个事件,可以获取到挂载的组件实例,或者 TemplateRef。这也让和挂载组件的交互变得十分方便了。
构造容器实例
不过既然说了是可以渲染到任意位置,那自然也包括 Angular 应用外部,要渲染到应用之外,就需要咱们通过构造函数创建容器实例。
这个容器类就是 DomPortalOutlet
,它是 PortalOutlet
BasePortalOutlet
으로도 정의됩니다. 이 클래스는 뷰와 유사하며 연결(컨테이너에 뷰 마운트), 분리(컨테이너에서 뷰 제거), 삭제( 컨테이너 삭제), isAttached(마운트된 뷰가 있는지 여부). 주요 구현은 DomPortalOutlet
클래스입니다. 세 가지 유형의 동적 보기를 마운트하는 데 사용됩니다. 동적 콘텐츠 만들기
먼저 세 가지 동적 뷰 생성을 살펴보겠습니다.constructor( private viewContainerRef: ViewContainerRef, @Inject(DOCUMENT) private document: any, private injector: Injector, private componentFactoryResolver: ComponentFactoryResolver ) { // 在<body>下创建外部宿主元素 const container = this.document.createElement('div'); container.classList.add('outside-portal-container'); this.outsideContainer = this.document.body.appendChild(container); // 获取应用实例 this.appRef = this.injector.get(ApplicationRef); // 创建外部容器 this.outsideOutlet = new DomPortalOutlet( this.outsideContainer, this.componentFactoryResolver, this.appRef, this.injector ); } // 在应用外部插入动态组件。 openComponentPortalOutSideAngularContext(): void { const componentPortal = new ComponentPortal(AlertComponent); const componentRef = this.outsideOutlet.attach(componentPortal); componentRef.instance.closeAlert.subscribe(() => { this.outsideOutlet.detach(); }); } // 在应用外部插入动态模板。 openTemplatePortalInsideAngularContext(): void { const templatePortal = new TemplatePortal(this.templatePortalContent, this.viewContainerRef); this.outsideOutlet.attach(templatePortal); }
ComponentPortal
개체를 생성한 다음 이를 뷰에 동적으로 삽입할 수 있습니다. entryComponents
에서 선언해야 합니다. 모듈이며 이 모듈은 지연 로드될 수 없습니다. 🎜TemplatePortal🎜🎜🎜TemplatePortal에는 구성요소보다 매개변수(ViewContainerRef)가 하나 더 있습니다. 이전 기사를 읽은 후에는 이에 대해 매우 익숙해질 것입니다. createEmbeddedView()
를 호출하여 내장된 뷰를 생성해야 합니다. 여기서는 생성자 주입을 통해 현재 구성요소의 ViewContainerRef
인스턴스를 직접 사용합니다. 🎜const injectionToken = new InjectionToken<any>('Sharing data with outside component portal'); const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: 'test value' }] });
// 重点是第四个参数 new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);
constructor(@Inject(injectionToken) public customData: any) {}
@ViewChild
를 통해 TemplatePortal
의 인스턴스를 얻을 수 있습니다. 🎜🎜🎜DomPortal🎜🎜🎜위의 예와 마찬가지로 @ViewChild
를 통해 템플릿 인스턴스를 가져와서 만들 수 있습니다. 또한 동적 DOM을 생성하려면 ElementRef와 유사하게 가져옵니다. 🎜// 重点是第三个参数 new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:'test values' });
anyPortal 모든 Portal 인스턴스는 현재 위치에 동적으로 렌더링됩니다. 🎜🎜기본 API 명령과 달리 어떤 유형의 포털인지 자동으로 확인할 수 있습니다. 또한 <code>attached
라는 추가 이벤트가 있습니다. 이 이벤트를 통해 마운트된 구성 요소 인스턴스 또는 TemplateRef를 가져올 수 있습니다. 이는 또한 장착된 구성 요소와의 상호 작용을 매우 편리하게 만듭니다. 🎜🎜🎜컨테이너 인스턴스 구축🎜🎜🎜하지만 어떤 위치에도 렌더링이 가능하다고 하니 당연히 Angular 애플리케이션 외부도 포함됩니다. 애플리케이션으로 렌더링합니다. 또한 생성자를 통해 컨테이너 인스턴스를 생성해야 합니다. 🎜🎜이 컨테이너 클래스는 PortalOutlet
의 구현 하위 클래스인 DomPortalOutlet
입니다. 구성 매개변수는 주로 다음과 같습니다: Element(마운트된 뷰의 DOM 노드), ComponentFactoryResolver(이전 기사와 동일, 구성 요소를 동적으로 빌드하는 데 사용됨), appRef(현재 Angular 애플리케이션의 전체 인스턴스), Injector(인젝터, 사용되는 인젝터) 종속성을 전달합니다). 🎜rrreee🎜뷰를 애플리케이션 외부의 DOM 요소에 마운트하는 것 외에도 뷰와 상호 작용할 수 있어야 합니다. 구성 요소는 종속성을 주입할 수 있고 템플릿은 컨텍스트 개체를 전달할 수 있습니다. 🎜rrreee🎜outsideContainer를 생성하는 코드를 약간 수정하고 customInjector를 매개 변수로 전달합니다(현재 구성 요소의 인젝터를 사용하는 대신)🎜rrreee🎜따라서 이 구성 요소는 다음 주입 토큰에 따라 종속성만 주입하면 됩니다.🎜rrreee🎜Give 템플릿 전달 컨텍스트는 상대적으로 간단합니다. TemplatePortal 개체를 생성할 때 컨텍스트 개체를 전달하면 됩니다. 🎜rrreee🎜🎜 요약🎜🎜🎜기본 API와 비교하여 CDK 포털은 주로 다음을 구현합니다. 🎜🎜🎜🎜응용 프로그램 외부 뷰의 동적 삽입 🎜 능력;외부에 삽입된 뷰 데이터와 상호 작용하는 기능
더 편리하고 유연한 명령.
이를 사용하면 동적 구성 요소 컨테이너, 팝업 창, 부동 메뉴를 생성하거나 로우 코드 디자인 플랫폼을 구축하는 것이 더 쉬워집니다.
프로젝트 소스 코드: https://github.com/locotor/angular-dynamic-view-example
온라인 예: https://coding-pages-bucket-1575455-8137703-14801-541995-1303365836.cos - website.ap-beijing.myqcloud.com/
프로그래밍 관련 지식을 더 보려면 프로그래밍 입문을 방문하세요! !
위 내용은 Angular CDK Portal을 사용하여 동적 콘텐츠를 생성하는 방법을 단계별로 알려드립니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!