使用垫子菜单作为上下文菜单:如何关闭打开的垫子菜单,并在另一个位置打开它
Using mat-menu as context menu: How to close opened mat-menu, and open it in another location
Angular: v8.2.8
我设法使用 mat-menu (angular material) 来模拟上下文菜单。在我的页面上右键单击,菜单出现在我的鼠标位置。
我想达到的效果:当我将鼠标移动到页面上的另一个位置时,我再次单击鼠标右键。我期待原始位置的菜单关闭并在新位置重新打开。
但实际上:当我右键单击时,没有任何反应,原始位置的菜单仍然打开。
事实上,我必须在原来的位置左键关闭打开的菜单,然后在新的鼠标位置右击打开菜单。
问题:知道如何实现我想要的吗?
@Component({
selector: 'fl-home',
template:`
<mat-menu #contextmenu>
<div >
<button mat-menu-item>Clear all Paths</button>
</div>
</mat-menu>
<div [matMenuTriggerFor]="contextmenu" [style.position]="'absolute'" [style.left.px]="menuX" [style.top.px]="menuY" ></div>
<div class="container" (contextmenu)="onTriggerContextMenu($event);"> ....</div>
`})
export class HomeComponent {
menuX:number=0
menuY:number=0
@ViewChild(MatMenuTrigger,{static:false}) menu: MatMenuTrigger;
onTriggerContextMenu(event){
event.preventDefault();
this.menuX = event.x - 10;
this.menuY = event.y - 10;
this.menu.closeMenu() // close existing menu first.
this.menu.openMenu()
}
}
只需添加 hasBackdrop=false
,如 <mat-menu ... [hasBackdrop]="false">
。
发生的情况是,当我右键单击后打开菜单时,会出现一个不可见的背景覆盖层,覆盖整个页面。无论我再次尝试右键单击什么,上下文菜单事件都不会触发,因此 onTriggerContextMenu()
不会被调用。通过将 hasBackgrop
设置为 false,将不会出现此叠加层。
也许你解决了它,但对于其他人来说,这是我解决这个问题的方法:
div 中的环绕菜单项,当鼠标离开菜单时(即 div)我将关闭它,因此您可以立即在另一个地方再次右键单击以再次显示上下文菜单....
<div (mouseleave)="mouseLeaveMenu()">
...menu items...
</div>
...
mouseLeaveMenu() {
if (this.contextMenu.menuOpened) this.contextMenu.closeMenu();
}
我的解决方案
ngOnInit(): void {
this.windowClickSubscription = fromEvent(window, 'click').subscribe((_) => {
if (this.contextMenu.menuOpen) {
this.contextMenu.closeMenu();
}
});
}
ngOnDestroy(): void {
this.windowClickSubscription && this.windowClickSubscription.unsubscribe();
this.menuSubscription && this.menuSubscription.unsubscribe();
}
onContextMenu(event: MouseEvent){
event.preventDefault();
this.menuSubscription && this.menuSubscription.unsubscribe();
this.menuSubscription = of(1)
.pipe(
tap(() => {
if (this.contextMenu.menuOpen) {
this.contextMenu.closeMenu();
}
this.contextMenuPosition.x = event.clientX;
this.contextMenuPosition.y = event.clientY;
}),
// delay(this.contextMenu.menuOpen ? 200 : 0),
delayWhen((_) => (this.contextMenu.menuOpen ? interval(200) : of(undefined))),
tap(async() => {
this.contextMenu.openMenu();
let backdrop: HTMLElement = null;
do {
await this.delay(100);
backdrop = document.querySelector(
'div.cdk-overlay-backdrop.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing'
) as HTMLElement;
} while (backdrop === null);
backdrop.style.pointerEvents = 'none';
})
)
.subscribe();
}
delay(delayInms: number) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, delayInms);
});
}
- 将属性
[hasBackdrop]="false"
添加到 mat-menu
- 更新
onTriggerContextMenu()
函数如下所示
- 终于;要关闭菜单,请在具有
(contextmenu)="..."
触发器的同一元素上正常单击,同时添加 (click)="themenu.closeMenu();"
onTriggerContextMenu(event: MouseEvent) {
this.themenu.closeMenu();
event.preventDefault();
this.menuX = event.clientX;
this.menuY = event.clientY;
this.themenu.menu.focusFirstItem('mouse');
this.themenu.openMenu();
}
如果您不想像大多数其他答案那样先关闭菜单,您可以手动设置菜单的位置:
// Assume you have the position in variables x and y
// Additionally you need to have the MatMenuTrigger (in this example in variable matMenuTrigger)
// this.cd.markForCheck() is important here if you just opened the menu with matMenuTrigger.openMenu()
const panelID = matMenuTrigger.menu.panelId;
const panelElement: HTMLElement = document.getElementById(panelID);
panelElement.style.position = "absolute";
panelElement.style.left = x + "px";
panelElement.style.top = y + "px";
Angular: v8.2.8
我设法使用 mat-menu (angular material) 来模拟上下文菜单。在我的页面上右键单击,菜单出现在我的鼠标位置。
我想达到的效果:当我将鼠标移动到页面上的另一个位置时,我再次单击鼠标右键。我期待原始位置的菜单关闭并在新位置重新打开。
但实际上:当我右键单击时,没有任何反应,原始位置的菜单仍然打开。
事实上,我必须在原来的位置左键关闭打开的菜单,然后在新的鼠标位置右击打开菜单。
问题:知道如何实现我想要的吗?
@Component({
selector: 'fl-home',
template:`
<mat-menu #contextmenu>
<div >
<button mat-menu-item>Clear all Paths</button>
</div>
</mat-menu>
<div [matMenuTriggerFor]="contextmenu" [style.position]="'absolute'" [style.left.px]="menuX" [style.top.px]="menuY" ></div>
<div class="container" (contextmenu)="onTriggerContextMenu($event);"> ....</div>
`})
export class HomeComponent {
menuX:number=0
menuY:number=0
@ViewChild(MatMenuTrigger,{static:false}) menu: MatMenuTrigger;
onTriggerContextMenu(event){
event.preventDefault();
this.menuX = event.x - 10;
this.menuY = event.y - 10;
this.menu.closeMenu() // close existing menu first.
this.menu.openMenu()
}
}
只需添加 hasBackdrop=false
,如 <mat-menu ... [hasBackdrop]="false">
。
发生的情况是,当我右键单击后打开菜单时,会出现一个不可见的背景覆盖层,覆盖整个页面。无论我再次尝试右键单击什么,上下文菜单事件都不会触发,因此 onTriggerContextMenu()
不会被调用。通过将 hasBackgrop
设置为 false,将不会出现此叠加层。
也许你解决了它,但对于其他人来说,这是我解决这个问题的方法: div 中的环绕菜单项,当鼠标离开菜单时(即 div)我将关闭它,因此您可以立即在另一个地方再次右键单击以再次显示上下文菜单....
<div (mouseleave)="mouseLeaveMenu()">
...menu items...
</div>
...
mouseLeaveMenu() {
if (this.contextMenu.menuOpened) this.contextMenu.closeMenu();
}
我的解决方案
ngOnInit(): void {
this.windowClickSubscription = fromEvent(window, 'click').subscribe((_) => {
if (this.contextMenu.menuOpen) {
this.contextMenu.closeMenu();
}
});
}
ngOnDestroy(): void {
this.windowClickSubscription && this.windowClickSubscription.unsubscribe();
this.menuSubscription && this.menuSubscription.unsubscribe();
}
onContextMenu(event: MouseEvent){
event.preventDefault();
this.menuSubscription && this.menuSubscription.unsubscribe();
this.menuSubscription = of(1)
.pipe(
tap(() => {
if (this.contextMenu.menuOpen) {
this.contextMenu.closeMenu();
}
this.contextMenuPosition.x = event.clientX;
this.contextMenuPosition.y = event.clientY;
}),
// delay(this.contextMenu.menuOpen ? 200 : 0),
delayWhen((_) => (this.contextMenu.menuOpen ? interval(200) : of(undefined))),
tap(async() => {
this.contextMenu.openMenu();
let backdrop: HTMLElement = null;
do {
await this.delay(100);
backdrop = document.querySelector(
'div.cdk-overlay-backdrop.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing'
) as HTMLElement;
} while (backdrop === null);
backdrop.style.pointerEvents = 'none';
})
)
.subscribe();
}
delay(delayInms: number) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, delayInms);
});
}
- 将属性
[hasBackdrop]="false"
添加到mat-menu
- 更新
onTriggerContextMenu()
函数如下所示 - 终于;要关闭菜单,请在具有
(contextmenu)="..."
触发器的同一元素上正常单击,同时添加(click)="themenu.closeMenu();"
onTriggerContextMenu(event: MouseEvent) {
this.themenu.closeMenu();
event.preventDefault();
this.menuX = event.clientX;
this.menuY = event.clientY;
this.themenu.menu.focusFirstItem('mouse');
this.themenu.openMenu();
}
如果您不想像大多数其他答案那样先关闭菜单,您可以手动设置菜单的位置:
// Assume you have the position in variables x and y
// Additionally you need to have the MatMenuTrigger (in this example in variable matMenuTrigger)
// this.cd.markForCheck() is important here if you just opened the menu with matMenuTrigger.openMenu()
const panelID = matMenuTrigger.menu.panelId;
const panelElement: HTMLElement = document.getElementById(panelID);
panelElement.style.position = "absolute";
panelElement.style.left = x + "px";
panelElement.style.top = y + "px";