Dan*_*iaz 5 angular-material2 angular angular-material-6
组件: https: //material.angular.io/components/snack-bar/examples
我有一个页面是父部分('#wrapper_container')。我想在“#wrapper_element”的子元素的中心弹出小吃栏。
谢谢
我们不能使用viewContainerRef选项将小吃栏附加到自定义容器。从 Angular Material文档来看,这个选项是:
出于依赖注入的目的,充当小吃栏父级的视图容器。###注意:这不会影响小吃栏在 DOM 中的插入位置。###
从ComponentPortal 文档中,我们可以找到更详细的描述viewContainerRef:
附加组件应该位于 Angular 的逻辑组件树中。这与组件渲染的位置不同,这是由PortalOutlet决定的。当主机位于 Angular 应用程序上下文之外时,原点是必需的。
打开小吃栏时检查 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)。现在,我们真正需要更改的是 DOM 中的位置OverlayContainer,根据docs,它是:
渲染所有单独覆盖元素的容器元素。
默认情况下,覆盖容器直接附加到文档正文。
从技术上讲,可以通过使用自定义提供程序来提供自定义覆盖容器,如文档中所述:
@NgModule({
providers: [{provide: OverlayContainer, useClass: AppOverlayContainer}],
// ...
})
export class MyModule { }
Run Code Online (Sandbox Code Playgroud)
这里发布的是一个简单的实现。
但不幸的是,它是一个单例并产生了一个潜在的问题:
MatDialog、MatSnackbar、MatTooltip和MatBottomSheet所有使用 的组件都OverlayContainer将在此 AppOverlayContainer 中打开:
由于这种情况远非理想,所以我编写的自定义提供程序 ( ) 需要更改only ondemandAppOverlayContainer的位置。overlaycontainer如果不调用,它将让overlaycontainerto 附加到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);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,在打开小吃店之前,我们必须调用:
AppOverlayContainer.appendToCustomWrapper(HTMLElement).
Run Code Online (Sandbox Code Playgroud)
方法,它将 附加overlaycontainer到我们的自定义包装元素。
当小吃店关闭时,最好致电:
AppOverlayContainer.appendToBody();
Run Code Online (Sandbox Code Playgroud)
方法,该方法从我们的自定义包装元素中删除overlaycontainer并将其重新附加到body.
另外,由于AppOverlayContainer将被注入到我们的组件中并且需要保持单例,因此我们将使用useExisting语法提供它:
providers: [
{provide: OverlayContainer, useExisting: AppOverlayContainer}
]
Run Code Online (Sandbox Code Playgroud)
例子:
如果我们想在自定义容器中显示小吃栏, #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>
Run Code Online (Sandbox Code Playgroud)
在我们的组件中,.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
});
}
}
Run Code Online (Sandbox Code Playgroud)
另外,我们需要一些必须插入到应用程序通用样式表中的 css:
.app-cdk-overlay-container {
position: absolute;
}
Run Code Online (Sandbox Code Playgroud)
完整的代码和演示位于 Stackblitz 上,我已经实现了多个小吃栏容器:
https://stackblitz.com/edit/angular-ivy-wxthzy
是的。viewContainerRef的属性将MatSnackBarConfig接受 aViewContainer作为附加它的位置Portal。
获取ViewContainerRef元素的 a 可以通过 ViewChild 查询或将其注入到放置在元素上的指令中来完成。前者是一个更简单的选择:
组件.html:
<div #wrapperContainer> </div>
Run Code Online (Sandbox Code Playgroud)
组件.ts:
@ViewChild('wrapperContainer', { read: ViewContainerRef }) container: ViewContainerRef;
ngAfterViewInit() {
this.something = this.snackBarService.open(
'message text',
'button text',
{ viewContainerRef: this.container}
);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4134 次 |
| 最近记录: |