noxi雑記

.NET、Angularまわりの小ネタブログ

Angular CDK OverlayでBackdropを使用する

Angular CDK Overlay の3本目の記事です。前回は画面に対する相対位置で表示する方法についてでした。

noxi515.hateblo.jp

今回は Angular CDK Overlay の backdrop についてです。 backdrop はその名の通り、オーバーレイ表示時にオーバーレイ要素の下に全画面の層を挿入する機能です。



環境

Angular CLI: 9.1.3
Node: 12.16.2
OS: win32 x64

Angular: 9.1.3
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.901.3
@angular-devkit/build-angular     0.901.3
@angular-devkit/build-optimizer   0.901.3
@angular-devkit/build-webpack     0.901.3
@angular-devkit/core              9.1.3
@angular-devkit/schematics        9.1.3
@angular/cdk                      9.2.1
@angular/material                 9.2.1
@ngtools/webpack                  9.1.3
@schematics/angular               9.1.3
@schematics/update                0.901.3
rxjs                              6.5.5
typescript                        3.8.3
webpack                           4.42.0

今回のコードは こちら に Push しています。

OverlayのBackdropを使用する

Backdropを表示する

Angular CDK Overlay の backdrop は、 Overlay を表示するときに backdrop: true を指定すると表示されるようになります。 backdrop が表示される事により下に表示されている Component のボタン操作などが一切できなくなります。

import type { GlobalPositionStrategy, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { Overlay } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import type { ComponentRef } from '@angular/core';
import { Component } from '@angular/core';
import { OverlayContentComponent } from './overlay-content/overlay-content.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {

  private _overlayRef?: OverlayRef;

  constructor(
    private readonly _overlay: Overlay,
  ) {
  }

  showOverlay() {
    let positionStrategy: GlobalPositionStrategy = this._overlay.position().global();
    positionStrategy = positionStrategy.centerVertically().centerHorizontally();

    const config: OverlayConfig = {
      positionStrategy,

      width: 'auto',
      height: 'auto',

      hasBackdrop: true,  // Backdrop表示
    };
    const overlayRef: OverlayRef = this._overlayRef = this._overlay.create(config);
    const componentPortal: ComponentPortal<OverlayContentComponent> = new ComponentPortal(OverlayContentComponent);
    const componentRef: ComponentRef<OverlayContentComponent> = overlayRef.attach(componentPortal);
  }
}

f:id:noxi515:20200426175340p:plain
Backdropが表示されたOverlay

f:id:noxi515:20200426175457p:plain
Backdrop表示のDOM階層

標準では Backdrop を表示すると半透明な黒の層が表示されます。

Backdrop を表示する際、 Backdrop 要素に追加する CSS クラスを指定することができます。この CSS クラスを指定した場合、デフォルトの Backdrop の半透明な黒は表示されなくなります。

showOverlay() {
  let positionStrategy: GlobalPositionStrategy = this._overlay.position().global();
  positionStrategy = positionStrategy.centerVertically().centerHorizontally();

  const config: OverlayConfig = {
    positionStrategy,

    width: 'auto',
    height: 'auto',

    hasBackdrop: true,                     // Backdrop表示
    backdropClass: ['app-backdrop-class'], // BackdropにCSSクラス適用
  };
  const overlayRef: OverlayRef = this._overlayRef = this._overlay.create(config);
  const componentPortal: ComponentPortal<OverlayContentComponent> = new ComponentPortal(OverlayContentComponent);
  const componentRef: ComponentRef<OverlayContentComponent> = overlayRef.attach(componentPortal);
}

f:id:noxi515:20200426175952p:plain
CSSクラス指定時のBackdrop DOM階層

Backdropのクリックを拾う

続いて表示した Backdrop に対して処理をしてみます。 Backdrop の HTMLElement 自体は OverlayRef#backdropElement にあります。ただクリックイベントを処理するだけであれば OverlayRef#backdropClick を使用します。

showOverlay() {
  let positionStrategy: GlobalPositionStrategy = this._overlay.position().global();
  positionStrategy = positionStrategy.centerVertically().centerHorizontally();

  const config: OverlayConfig = {
    positionStrategy,

    width: 'auto',
    height: 'auto',

    hasBackdrop: true,
    backdropClass: ['app-backdrop-class'],
  };
  const overlayRef: OverlayRef = this._overlayRef = this._overlay.create(config);
  const componentPortal: ComponentPortal<OverlayContentComponent> = new ComponentPortal(OverlayContentComponent);
  const componentRef: ComponentRef<OverlayContentComponent> = overlayRef.attach(componentPortal);

  // OverlayのBackdropクリックでオーバーレイを非表示に
  overlayRef.backdropClick().subscribe(() => overlayRef.dispose());
}

よくある Backdrop をクリックしたらオーバーレイが消える実装です。1行でサクッと実装出来るのはとても良いです。