有没有办法修改MatDialog的覆盖顺序?
Is there any way to modify the MatDialog overlay order?
我想在我的应用程序中实现基本的对话框处理,有 2 个功能:
- 关闭所有打开的对话框:使用 MatDialog.closeAll();
很简单
- 允许用户在打开的对话框之间切换!
这对我来说是个问题,因为似乎没有让对话框按顺序排在第一个的功能。
我可以用MatDialog.openDialogs查询所有打开的对话框,我可以显示它们的名称供用户选择。之后,我尝试将面板 class 添加到修改 z-index 的点击面板,但没有任何反应。
有什么解决办法?
我的代码:
HTML 菜单模板,用于处理对话操作:
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="closeAll()">
<mat-icon>close_all</mat-icon>
<span>Close all</span>
</button>
<mat-divider></mat-divider>
<button
(click)="focusDialog(dialog, $event)"
*ngFor="let dialog of this.dialog.openDialogs"
mat-menu-item
>
<mat-icon>preview</mat-icon>
<span>{{ dialog.componentInstance.data.title }}</span>
</button>
</mat-menu>
按钮单击事件处理程序:
focusDialog(dialogRef: MatDialogRef<any>, e: any) {
e.stopPropagation();
this.dialog.openDialogs.forEach((dialog) => {
dialog.removePanelClass('dialog-focus');
});
dialogRef.addPanelClass('dialog-focus');
}
对话焦点 css class:
.dialog-focus .mat-dialog-container{
z-index: 1000 !important;
}
编辑:
我似乎无法通过 z-index 实现任何效果,但我可以将对话框的显示设置为 'block' 或 'none' 这样,我就可以看到首选对话框。
问题是:我无法与之交互! 最后打开的对话框的叠加层仍然存在。我怎样才能让它消失,然后在用户切换回其相关对话框时再次使用它?
focusDialog(dialogRef: MatDialogRef<any>, e: any) {
e.stopPropagation();
this.dialog.openDialogs.forEach((dialog) => {
dialog.removePanelClass('dialog-focus');
dialog.addPanelClass('dialog-background');
});
dialogRef.addPanelClass('dialog-focus');
dialogRef.removePanelClass('dialog-background');
}
.dialog-focus .mat-dialog-container {
z-index: 1000 !important;
display: block;
}
.dialog-background .mat-dialog-container {
z-index: 1 !important;
display: none;
}
我检查了 HTML 树,打开的对话框和叠加层似乎是兄弟。
A mat-dialog 添加一个 div with class 'cdk-global-overlay-wrapper' to a div with class 'cdk-overlay-container' 在底部.html
所以你可以改变元素的位置。但是你需要在“纯javascript”中制作。
我们可以在模式的每个组件中更改创建功能的元素的位置,但最好是由 parent 来完成工作(您也可以委托服务 (*))
因此,我们在模态组件的构造函数中注入 elementRef 并声明一个输出
@Output() toTop:EventEmitter<any>=new EventEmitter<any>()
constructor(public el: ElementRef){}
当我们想要鼠标按下时,我们会发出事件。在this stackbliz中,将cdkdrag添加到我选择的组件的“header”中,也将鼠标向下“拖动”
<!--as I declared in constructor as public the "el" we can use in .html-->
<h1 (mousedown)="toTop.emit(el)" mat-dialog-title cdkDragHandle
>Hi {{data.name}}</h1>
好吧,在 parent 中,我们需要一个函数让我们的元素置顶
toTop(wich:ElementRef) {
const elements = document.getElementsByClassName(
'cdk-global-overlay-wrapper'
);
for (let i = 0; i < elements.length; ++i) {
const el = elements[i];
if (el.contains(wich.nativeElement)) {
const parent = el.parentNode;
const last = parent.lastChild;
if (last != el){
last.parentNode.insertBefore(el, last.nextSibling);
}
break;
}
}
}
并且,基于此另一个 SO 将 mat-dialog 与我们制作的 parent 进行通信,例如
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '250px',
hasBackdrop: false,
data: {name: this.name, animal: this.animal}
});
const sub = dialogRef.componentInstance.toTop.subscribe((el) => {
this.toTop(el)
});
(*) 使用服务只需使用函数
声明您的服务
toTop(wich:ElementRef) {
....
}
在模态组件中注入服务
constructor(public modalService:ModalService,
public el:ElementRef){}
并使用
<h1 (mousedown)="modalService.toTop(el)" mat-dialog-title cdkDragHandle
>Hi {{data.name}}</h1>
根据 Eliseo 的 回答,我想到了另一个更适合我的应用程序的解决方案:
我不希望父组件管理覆盖顺序更改,因为我认为它更通用,如果我创建一个负责所有对话框操作的组件,并接受一个组件作为输入来加载它的模板里面是自己。这样我就可以在我的应用程序中的任何地方轻松打开一个 dilaog,并在对话框中打开对话框等等。
根据 Eliseo 的回答,不需要面板 class 修改。重新排序 cdk-global-overlay-wrapper 元素就足够了。
Stackblitz link 解决方案:
原始问题中的文件如何更改:
HTML
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="closeAll()">
<mat-icon>close_all</mat-icon>
<span>Close all</span>
</button>
<mat-divider></mat-divider>
<button
(click)="focusDialog(dialog, $event)"
*ngFor="let dialog of this.dialog.openDialogs"
mat-menu-item
>
<mat-icon>preview</mat-icon>
<span>{{ dialog.componentInstance.data.title }}</span>
</button>
</mat-menu>
focusDialog(dialogRef: MatDialogRef<any>, e: any) {
const cdkOverlayWrappers = document.getElementsByClassName(
'cdk-global-overlay-wrapper'
);
for (let i = 0; i < cdkOverlayWrappers.length; i++) {
const wrapper = cdkOverlayWrappers[i];
if (wrapper.contains(dialogRef.componentInstance.el.nativeElement)) {
const parent = wrapper.parentNode!;
const last = parent.lastChild;
if (last != wrapper)
last!.parentNode!.insertBefore(wrapper, last!.nextSibling);
break;
}
}
}
我想在我的应用程序中实现基本的对话框处理,有 2 个功能:
- 关闭所有打开的对话框:使用 MatDialog.closeAll(); 很简单
- 允许用户在打开的对话框之间切换!
这对我来说是个问题,因为似乎没有让对话框按顺序排在第一个的功能。
我可以用MatDialog.openDialogs查询所有打开的对话框,我可以显示它们的名称供用户选择。之后,我尝试将面板 class 添加到修改 z-index 的点击面板,但没有任何反应。
有什么解决办法?
我的代码:
HTML 菜单模板,用于处理对话操作:
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="closeAll()">
<mat-icon>close_all</mat-icon>
<span>Close all</span>
</button>
<mat-divider></mat-divider>
<button
(click)="focusDialog(dialog, $event)"
*ngFor="let dialog of this.dialog.openDialogs"
mat-menu-item
>
<mat-icon>preview</mat-icon>
<span>{{ dialog.componentInstance.data.title }}</span>
</button>
</mat-menu>
按钮单击事件处理程序:
focusDialog(dialogRef: MatDialogRef<any>, e: any) {
e.stopPropagation();
this.dialog.openDialogs.forEach((dialog) => {
dialog.removePanelClass('dialog-focus');
});
dialogRef.addPanelClass('dialog-focus');
}
对话焦点 css class:
.dialog-focus .mat-dialog-container{
z-index: 1000 !important;
}
编辑:
我似乎无法通过 z-index 实现任何效果,但我可以将对话框的显示设置为 'block' 或 'none' 这样,我就可以看到首选对话框。 问题是:我无法与之交互! 最后打开的对话框的叠加层仍然存在。我怎样才能让它消失,然后在用户切换回其相关对话框时再次使用它?
focusDialog(dialogRef: MatDialogRef<any>, e: any) {
e.stopPropagation();
this.dialog.openDialogs.forEach((dialog) => {
dialog.removePanelClass('dialog-focus');
dialog.addPanelClass('dialog-background');
});
dialogRef.addPanelClass('dialog-focus');
dialogRef.removePanelClass('dialog-background');
}
.dialog-focus .mat-dialog-container {
z-index: 1000 !important;
display: block;
}
.dialog-background .mat-dialog-container {
z-index: 1 !important;
display: none;
}
我检查了 HTML 树,打开的对话框和叠加层似乎是兄弟。
A mat-dialog 添加一个 div with class 'cdk-global-overlay-wrapper' to a div with class 'cdk-overlay-container' 在底部.html
所以你可以改变元素的位置。但是你需要在“纯javascript”中制作。
我们可以在模式的每个组件中更改创建功能的元素的位置,但最好是由 parent 来完成工作(您也可以委托服务 (*))
因此,我们在模态组件的构造函数中注入 elementRef 并声明一个输出
@Output() toTop:EventEmitter<any>=new EventEmitter<any>()
constructor(public el: ElementRef){}
当我们想要鼠标按下时,我们会发出事件。在this stackbliz中,将cdkdrag添加到我选择的组件的“header”中,也将鼠标向下“拖动”
<!--as I declared in constructor as public the "el" we can use in .html-->
<h1 (mousedown)="toTop.emit(el)" mat-dialog-title cdkDragHandle
>Hi {{data.name}}</h1>
好吧,在 parent 中,我们需要一个函数让我们的元素置顶
toTop(wich:ElementRef) {
const elements = document.getElementsByClassName(
'cdk-global-overlay-wrapper'
);
for (let i = 0; i < elements.length; ++i) {
const el = elements[i];
if (el.contains(wich.nativeElement)) {
const parent = el.parentNode;
const last = parent.lastChild;
if (last != el){
last.parentNode.insertBefore(el, last.nextSibling);
}
break;
}
}
}
并且,基于此另一个 SO 将 mat-dialog 与我们制作的 parent 进行通信,例如
const dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
width: '250px',
hasBackdrop: false,
data: {name: this.name, animal: this.animal}
});
const sub = dialogRef.componentInstance.toTop.subscribe((el) => {
this.toTop(el)
});
(*) 使用服务只需使用函数
声明您的服务toTop(wich:ElementRef) {
....
}
在模态组件中注入服务
constructor(public modalService:ModalService,
public el:ElementRef){}
并使用
<h1 (mousedown)="modalService.toTop(el)" mat-dialog-title cdkDragHandle
>Hi {{data.name}}</h1>
根据 Eliseo 的 回答,我想到了另一个更适合我的应用程序的解决方案:
我不希望父组件管理覆盖顺序更改,因为我认为它更通用,如果我创建一个负责所有对话框操作的组件,并接受一个组件作为输入来加载它的模板里面是自己。这样我就可以在我的应用程序中的任何地方轻松打开一个 dilaog,并在对话框中打开对话框等等。
根据 Eliseo 的回答,不需要面板 class 修改。重新排序 cdk-global-overlay-wrapper 元素就足够了。
Stackblitz link 解决方案:
原始问题中的文件如何更改:
HTML
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="closeAll()">
<mat-icon>close_all</mat-icon>
<span>Close all</span>
</button>
<mat-divider></mat-divider>
<button
(click)="focusDialog(dialog, $event)"
*ngFor="let dialog of this.dialog.openDialogs"
mat-menu-item
>
<mat-icon>preview</mat-icon>
<span>{{ dialog.componentInstance.data.title }}</span>
</button>
</mat-menu>
focusDialog(dialogRef: MatDialogRef<any>, e: any) {
const cdkOverlayWrappers = document.getElementsByClassName(
'cdk-global-overlay-wrapper'
);
for (let i = 0; i < cdkOverlayWrappers.length; i++) {
const wrapper = cdkOverlayWrappers[i];
if (wrapper.contains(dialogRef.componentInstance.el.nativeElement)) {
const parent = wrapper.parentNode!;
const last = parent.lastChild;
if (last != wrapper)
last!.parentNode!.insertBefore(wrapper, last!.nextSibling);
break;
}
}
}