返回

从头了解 @angular/cdk 之 Portal

前端

前言

最近在学习 React 时,发现 React 提供了 Portals 技术,该技术主要用来把子节点动态的显示到父节点外的 DOM 节点上,该技术的一个经典用例应该就是 Dialog 了。设想一下在设计 Dialog 时所需要的主要功能点:

  • 当点击一个 button 时,一般需要在 Dialog 的内容出现前先让 Dialog 的容器 Div 显示出来。
  • Dialog 的内容一般是由开发者定义好的一个组件,可以在不同的组件中复用。
  • Dialog 显示和隐藏的控制权一般由 Dialog 所在的组件负责。

通过分析以上需求可以发现,本质上我们需要的功能是:

  • 如何创建一个组件的实例并把它插入到另一个组件的 DOM 结构中。
  • 如何在不同的组件间传递数据和控制组件。

而 Angular Material 团队提供的 Portal 机制正是满足了我们的以上需求。本文将对 Portal 机制进行深入分析,探讨其原理和使用场景,并结合实例演示如何使用 Portal 在 Angular 应用程序中实现跨组件通信和动态渲染。

Portal 简介

Portal 是 Angular Material 团队提供的一个库,它允许开发者把组件实例动态地插入到 DOM 的不同位置,而不仅仅是组件所在的位置。Portal 机制使得组件可以跨组件边界进行通信和渲染,从而实现了组件之间的解耦和重用。

Portal 主要由以下几个部分组成:

  • Portal: Portal 是一个抽象类,它定义了创建和附加 Portal 实例所需的接口。
  • PortalHost: PortalHost 是一个接口,它定义了如何将 Portal 实例附加到 DOM 的方法。
  • DomPortal: DomPortal 是一个具体类,它允许开发者将 DOM 元素作为 Portal 实例。
  • TemplatePortal: TemplatePortal 是一个具体类,它允许开发者将模板作为 Portal 实例。
  • CdkPortalOutlet: CdkPortalOutlet 是一个指令,它允许开发者将 Portal 实例附加到 DOM 中。

Portal 的使用场景

Portal 机制可以应用于各种场景,其中一些常见的场景包括:

  • 模态对话框 :Portal 可以用来创建模态对话框,模态对话框是一个覆盖整个屏幕的弹出窗口,用户必须在与对话框交互后才能继续与应用程序的其他部分交互。
  • 侧边栏 :Portal 可以用来创建侧边栏,侧边栏是一个位于应用程序一侧的垂直面板,它可以包含菜单、工具栏或其他控件。
  • 工具提示 :Portal 可以用来创建工具提示,工具提示是一个出现在元素附近的弹出窗口,当用户将鼠标悬停在元素上时,工具提示就会出现。
  • 动态加载组件 :Portal 可以用来动态加载组件,动态加载组件是指在运行时将组件添加到应用程序中,而不是在编译时就将其包含在应用程序中。

Portal 的原理

Portal 机制的工作原理是:

  1. 创建一个 Portal 实例。
  2. 将 Portal 实例附加到一个 PortalHost 实例。
  3. PortalHost 实例将 Portal 实例的内容渲染到 DOM 中。

Portal 实例和 PortalHost 实例之间的通信是通过 attachdetach 方法实现的。当调用 attach 方法时,PortalHost 实例会将 Portal 实例的内容渲染到 DOM 中。当调用 detach 方法时,PortalHost 实例会从 DOM 中移除 Portal 实例的内容。

Portal 的使用示例

Portal 机制的使用非常简单,下面是一个使用 Portal 创建模态对话框的示例:

import { Component, ViewChild } from '@angular/core';
import { Portal, DomPortalOutlet } from '@angular/cdk/portal';

@Component({
  selector: 'app-modal-dialog',
  template: `<ng-template #dialogContent>
    <div>
      <h1>Dialog Title</h1>
      <p>Dialog Content</p>
      <button (click)="closeDialog()">Close</button>
    </div>
  </ng-template>

  <ng-template #dialogContainer>
    <div class="cdk-overlay-container"></div>
  </ng-template>
})
export class ModalDialogComponent {
  @ViewChild(DomPortalOutlet) portalOutlet: DomPortalOutlet;

  private portal: Portal<any>;

  openDialog() {
    this.portal = new DomPortal(this.dialogContent);
    this.portalOutlet.attach(this.portal);
  }

  closeDialog() {
    this.portalOutlet.detach();
  }
}

在上面的示例中,我们创建了一个 ModalDialogComponent 组件,该组件包含了一个模态对话框的内容和一个模态对话框的容器。当用户点击 openDialog() 方法时,Portal 实例就会被创建并附加到 PortalHost 实例,模态对话框的内容就会被渲染到 DOM 中。当用户点击 closeDialog() 方法时,Portal 实例就会从 PortalHost 实例中分离,模态对话框的内容就会从 DOM 中移除。

结语

Portal 机制是一个非常强大的工具,它可以帮助开发者实现各种复杂的 UI 交互。本文对 Portal 机制进行了深入分析,探讨了其原理和使用场景,并结合实例演示了如何使用 Portal 在 Angular 应用程序中实现跨组件通信和动态渲染。希望本文能够帮助读者更好地理解和使用 Portal 机制。