File

src/app/component/notification/notification-container.ts

Extends

BasePortalOutlet

Implements

OnDestroy

Metadata

changeDetection ChangeDetectionStrategy.OnPush
encapsulation ViewEncapsulation.None
host {
}
moduleId module.id
selector notification-container
styleUrls notification-container.scss
templateUrl notification-container.html

Index

Properties
Methods

Constructor

constructor(_ngZone: NgZone, _elementRef: ElementRef, _changeDetectorRef: ChangeDetectorRef)
Parameters :
Name Type Optional
_ngZone NgZone No
_elementRef ElementRef No
_changeDetectorRef ChangeDetectorRef No

Methods

Private _assertNotAttached
_assertNotAttached()
Returns : void
Private _completeExit
_completeExit()
Returns : void
attachComponentPortal
attachComponentPortal(portal: ComponentPortal)
Type parameters :
  • T
Parameters :
Name Type Optional
portal ComponentPortal<T> No
Returns : ComponentRef<T>
attachTemplatePortal
attachTemplatePortal(portal: TemplatePortal)
Type parameters :
  • C
Parameters :
Name Type Optional
portal TemplatePortal<C> No
Returns : EmbeddedViewRef<C>
enter
enter()
Returns : void
exit
exit()
Returns : Observable<void>
ngOnDestroy
ngOnDestroy()
Returns : void
onAnimationEnd
onAnimationEnd(event: AnimationEvent)
Parameters :
Name Type Optional
event AnimationEvent No
Returns : void

Properties

_animationState
Type : string
Default value : 'void'
Private _destroyed
Default value : false
Readonly _onEnter
Type : Subject<any>
Default value : new Subject()
Readonly _onExit
Type : Subject<any>
Default value : new Subject()
_portalOutlet
Type : CdkPortalOutlet
Decorators :
@ViewChild(CdkPortalOutlet, {static: false})
notificationConfig
Type : NotificationConfig
import {
  Component,
  ComponentRef,
  EmbeddedViewRef,
  ViewChild,
  NgZone,
  OnDestroy,
  ElementRef,
  ChangeDetectionStrategy,
  ViewEncapsulation,
  ChangeDetectorRef
} from '@angular/core';
import { AnimationEvent } from '@angular/animations';
import {
  BasePortalOutlet,
  ComponentPortal,
  CdkPortalOutlet,
  TemplatePortal
} from '@angular/cdk/portal';
import { take } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';

import { NotificationConfig } from './notification.config';
import { NotificationAnimations } from './notification.animation';

@Component({
  moduleId: module.id,
  selector: 'notification-container',
  templateUrl: 'notification-container.html',
  styleUrls: ['notification-container.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
  animations: [NotificationAnimations.notificationState],
  host: {
    class: 'notification-container',
    '[@state]': '_animationState',
    '(@state.done)': 'onAnimationEnd($event)'
  }
})
export class NotificationContainer extends BasePortalOutlet
  implements OnDestroy {
  private _destroyed = false;

  @ViewChild(CdkPortalOutlet, { static: false }) _portalOutlet: CdkPortalOutlet;

  readonly _onExit: Subject<any> = new Subject();
  readonly _onEnter: Subject<any> = new Subject();

  _animationState = 'void';
  notificationConfig: NotificationConfig;

  constructor(
    private _ngZone: NgZone,
    private _elementRef: ElementRef,
    private _changeDetectorRef: ChangeDetectorRef
  ) {
    super();
  }

  attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
    return this._portalOutlet.attachComponentPortal(portal);
  }

  attachTemplatePortal<C>(portal: TemplatePortal<C>): EmbeddedViewRef<C> {
    return this._portalOutlet.attachTemplatePortal(portal);
  }

  onAnimationEnd(event: AnimationEvent) {
    const { fromState, toState } = event;

    if (
      (toState === 'void' && fromState !== 'void') ||
      toState.startsWith('hidden')
    ) {
      this._completeExit();
    }

    if (toState.startsWith('visible')) {
      const onEnter = this._onEnter;

      this._ngZone.run(() => {
        onEnter.next();
        onEnter.complete();
      });
    }
  }

  enter(): void {
    if (!this._destroyed) {
      this._animationState = `visible-${
        this.notificationConfig.verticalPosition
        }`;
      this._changeDetectorRef.detectChanges();
    }
  }

  exit(): Observable<void> {
    this._animationState = `hidden-${this.notificationConfig.verticalPosition}`;
    return this._onExit;
  }

  ngOnDestroy() {
    this._destroyed = true;
    this._completeExit();
  }

  private _completeExit() {
    this._ngZone.onMicrotaskEmpty
      .asObservable()
      .pipe(take(1))
      .subscribe(() => {
        this._onExit.next();
        this._onExit.complete();
      });
  }

  private _assertNotAttached() {
    if (this._portalOutlet.hasAttached()) {
      throw Error('已存在');
    }
  }
}
<ng-template cdkPortalOutlet></ng-template>

notification-container.scss

$notification-min-width: 300px !default;
$notification-max-width: 600px !default;

.notification-container {
  display: block;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""