gpt4 book ai didi

angular - 是否可以在特定 DOM 元素上打开 Angular/Material Snackbar?

转载 作者:行者123 更新时间:2023-12-04 02:58:29 26 4
gpt4 key购买 nike

组件:https://material.angular.io/components/snack-bar/examples

我有一个页面是父部分('#wrapper_container')。我想在“#wrapper_element”的子元素的中心弹出 snackbar 。

谢谢

最佳答案

我们不能使用 viewContainerRef选项,以便将 snackbar 附加到自定义容器。来自 Angular Material docs ,这个选项是:

The view container that serves as the parent for the snackbar for the purposes of dependency injection.###Note: this does not affect where the snackbar is inserted in the DOM.###


来自 ComponentPortal documentation ,我们可以找到更详细的描述 viewContainerRef :

Where the attached component should live in Angular's logical component tree. This is different from where the component renders, which is determined by the PortalOutlet. The origin is necessary when the host is outside of the Angular application context.


当快餐店打开时检查 DOM 时,我们会发现以下组件层次结构:
  • Body - <body>
  • OverlayContainer - <div class="cdk-overlay-container"></div>
  • Overlay - <div id="cdk-overlay-{id}" class="cdk-overlay-pane">
  • ComponentPortal - <snack-bar-container></snack-bar-container>
  • Component - 我们的Snackbar ,打开方式如下:this.snackbar.open(message, action) .

  • 现在,我们真正需要改变的是 OverlayContainer 在 DOM 中的位置。 ,其中,根据 docs , 是:

    the container element in which all individual overlay elements arerendered.

    By default, the overlay container is appended directly to the document body.


    从技术上讲,可以提供 定制 覆盖容器,如 documentation 中所述,通过使用自定义提供程序:
    @NgModule({
    providers: [{provide: OverlayContainer, useClass: AppOverlayContainer}],
    // ...
    })
    export class MyModule { }
    一个简单的实现是发布的 here .

    但是,不幸的是,它是 单例 并产生一个潜在的问题:
    MatDialog , MatSnackbar , MatTooltip , MatBottomSheet以及所有使用 OverlayContainer 的组件将在此 AppOverlayContainer 内打开:
    由于这种情况远非理想,我编写的自定义提供程序 ( AppOverlayContainer) 需要更改 overlaycontainer 的位置。仅按需提供。如果不调用,它将让 overlaycontainer附加到 body .
    代码是:
    import { Injectable } from '@angular/core';
    import { OverlayContainer } from '@angular/cdk/overlay';

    @Injectable({
    providedIn: 'root'
    })
    export class AppOverlayContainer extends OverlayContainer {
    appOverlayContainerClass = 'app-cdk-overlay-container';

    /**
    * Append the OverlayContainer to the custom wrapper element
    */
    public appendToCustomWrapper(wrapperElement: HTMLElement): void {
    if (wrapperElement === null) {
    return;
    }

    // this._containerElement is 'cdk-overlay-container'
    if (!this._containerElement) {
    super._createContainer();
    }

    // add a custom css class to the 'cdk-overlay-container' for styling purposes
    this._containerElement.classList.add(this.appOverlayContainerClass);

    // attach the 'cdk-overlay-container' to our custom wrapper
    wrapperElement.appendChild(this._containerElement);
    }

    /**
    * Remove the OverlayContainer from the custom element and append it to body
    */
    public appendToBody(): void {
    if (!this._containerElement) {
    return;
    }

    // remove the custom css class from the 'cdk-overlay-container'
    this._containerElement.classList.remove(this.appOverlayContainerClass);

    // re-attach the 'cdk-overlay-container' to body
    this._document.body.appendChild(this._containerElement);
    }

    }
    因此,在打开 snackbar 之前,我们必须调用:
    AppOverlayContainer.appendToCustomWrapper(HTMLElement).
    方法,它附加 overlaycontainer到我们的自定义包装元素。
    当 snackbar 关门时,最好调用以下电话:
    AppOverlayContainer.appendToBody();
    方法,删除 overlaycontainer来自我们的自定义包装元素并将其重新附加到 body .
    此外,由于 AppOverlayContainer将被注入(inject)到我们的组件中并且需要保持为单例,我们将使用 useExisting 来提供它句法:
    providers: [
    {provide: OverlayContainer, useExisting: AppOverlayContainer}
    ]
    示例:
    如果我们想在自定义容器中显示小吃吧, #appOverlayWrapperContainer1 :
    <button mat-raised-button 
    (click)="openSnackBar(appOverlayWrapperContainer1, 'Snackbar 1 msg', 'Action 1')">
    Open Snackbar 1
    </button>
    <div class="app-overlay-wrapper-container" #appOverlayWrapperContainer1>
    Snackbar 1 overlay attached to this div
    </div>
    在我们的组件中 .ts我们有:
    import { AppOverlayContainer } from './app-overlay-container';

    export class SnackBarOverviewExample {

    constructor(
    private _snackBar: MatSnackBar,
    private _appOverlayContainer: AppOverlayContainer
    ) { }

    openSnackBar(
    overlayContainerWrapper: HTMLElement,
    message: string,
    action: string
    ) {

    if (overlayContainerWrapper === null) {
    return;
    }

    this.appOverlayContainer.appendToCustomWrapper(overlayContainerWrapper);

    this.snackbarRef = this._snackBar.open(message, action, {
    duration: 2000
    });
    }
    }
    此外,我们需要一些必须插入到应用通用样式表中的 css:
    .app-cdk-overlay-container {
    position: absolute;
    }
    完整的代码和演示在 Stackblitz 上,我是否已经实现了多个 snackbar 容器:
    https://stackblitz.com/edit/angular-ivy-wxthzy

    关于angular - 是否可以在特定 DOM 元素上打开 Angular/Material Snackbar?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51506486/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com