>  기사  >  웹 프론트엔드  >  Angular CDK Portal을 사용하여 동적 콘텐츠를 생성하는 방법을 단계별로 알려드립니다.

Angular CDK Portal을 사용하여 동적 콘텐츠를 생성하는 방법을 단계별로 알려드립니다.

青灯夜游
青灯夜游앞으로
2021-08-17 10:37:292642검색

Angular CDK Portal을 사용하여 동적 콘텐츠를 생성하는 방법을 단계별로 알려드립니다.

이전에 네이티브 API의 동적 뷰 삽입을 소개한 적이 있는데, 이 기능은 이미 대부분의 사용 시나리오를 충족할 수 있습니다. 하지만 아직 Angular 애플리케이션 외부에 콘텐츠를 삽입해야 하는 필요성이 해결되지 않았으며 명령이 동적으로 삽입된 구성 요소와 입력 및 출력 상호 작용을 할 수 없습니다.

다행히 Angular는 동적 뷰 생성을 지원하는 "포털"을 포함한 다양한 Angular 구성 요소 개발을 위한 기본 도구로 구성 요소 개발 키트 세트인 CDK(Component Dev Kit)를 공식적으로 제공합니다.

이 "동적 보기"는 각각 세 가지 포털 유형(ComponentPortal, TemplatePortal, DomPortal)에 해당하는 구성 요소, TemplateRef 또는 DOM 요소일 수 있습니다. 그 중 세 가지의 추상 일반 기본 클래스는 Portal<t></t>이며, 여기에는 세 가지 메서드가 있습니다: attachment(컨테이너에 마운트), detach(컨테이너에서 제거), isAttached(뷰 여부 결정) 마운트된 상태입니다.) Portal8742468051c85b06f0a0af9e3e506b5c,有三个方法: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(&#39;testTemplate&#39;) 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(&#39;domPortalContent&#39;) 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 클래스입니다. 세 가지 유형의 동적 보기를 마운트하는 데 사용됩니다.

동적 콘텐츠 만들기

먼저 세 가지 동적 뷰 생성을 살펴보겠습니다.

ComponentPortal

네이티브 API에 비해 동적 구성 요소를 만드는 것은 매우 간단합니다. 구성 요소 클래스를 ComponentPortal 생성자이면 충분합니다.

constructor(
  private viewContainerRef: ViewContainerRef,
  @Inject(DOCUMENT) private document: any,
  private injector: Injector,
  private componentFactoryResolver: ComponentFactoryResolver
) {
  // 在<body>下创建外部宿主元素
  const container = this.document.createElement(&#39;div&#39;);
  container.classList.add(&#39;outside-portal-container&#39;);
  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 개체를 생성한 다음 이를 뷰에 동적으로 삽입할 수 있습니다.
  • ✨참고: Angular 9 이후 버전에서는 Ivy 컴파일러를 사용하는 것이 좋습니다. 이전 버전의 컴파일러인 경우 전달된 구성 요소 클래스를 entryComponents에서 선언해야 합니다. 모듈이며 이 모듈은 지연 로드될 수 없습니다.

    🎜TemplatePortal🎜🎜🎜TemplatePortal에는 구성요소보다 매개변수(ViewContainerRef)가 하나 더 있습니다. 이전 기사를 읽은 후에는 이에 대해 매우 익숙해질 것입니다. createEmbeddedView()를 호출하여 내장된 뷰를 생성해야 합니다. 여기서는 생성자 주입을 통해 현재 구성요소의 ViewContainerRef 인스턴스를 직접 사용합니다. 🎜
    const injectionToken = new InjectionToken<any>(&#39;Sharing data with outside component portal&#39;);
    const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: &#39;test value&#39; }] });
    // 重点是第四个参数
    new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);
    🎜TemplatePortal에는 생성자 외에도 쉽게 생성할 수 있는 명령(CdkPortal)도 있습니다. 🎜
    constructor(@Inject(injectionToken) public customData: any) {}
    🎜그러면 @ViewChild를 통해 TemplatePortal의 인스턴스를 얻을 수 있습니다. 🎜🎜🎜DomPortal🎜🎜🎜위의 예와 마찬가지로 @ViewChild를 통해 템플릿 인스턴스를 가져와서 만들 수 있습니다. 또한 동적 DOM을 생성하려면 ElementRef와 유사하게 가져옵니다. 🎜
    // 重点是第三个参数
    new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:&#39;test values&#39; });
    rrreee🎜는 이 DOM을 어떤 위치로든 동적으로 이동할 수 있습니다. 전송 후에는 원래 데이터 바인딩이나 바인딩된 지침이 더 이상 업데이트되지 않을 수 있다는 점에 유의해야 합니다. 🎜🎜🎜컨테이너에 삽입🎜🎜🎜앞서 세 가지 유형의 Portal을 어떤 위치로든 렌더링할 수 있다고 했는데 구체적으로 어떻게 렌더링하나요? 🎜🎜🎜CdkPortOutlet🎜🎜🎜가장 쉬운 방법은 CdkPortOutlet 명령을 전달하는 것입니다. 🎜rrreee🎜위의 세 가지 값을 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제