Sai*_*aif 10 material-design angular-material angular-material2 angular angular-material-6
这个问题是参考这个 Github问题,mat-menu使用鼠标悬停不能切换,我基本上试图用角度材料的菜单替换基于bootstrap的水平导航菜单.阻止我复制基于bootstrap的菜单的唯一一件事就是mat-menu在悬停时打开和关闭.正如上面的Github问题所提到的,有一些解决方法可以实现我想要的,比如使用mouseEnter
(mouseenter)="menuTrigger.openMenu()"
Run Code Online (Sandbox Code Playgroud)
或者在Mat-menu中添加一个span以便绑定mat-menu,
<mat-menu #menu="matMenu" overlapTrigger="false">
<span (mouseleave)="menuTrigger.closeMenu()">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</span>
</mat-menu>
Run Code Online (Sandbox Code Playgroud)
但是没有一个解决方案似乎涵盖了每一个小场景,
例如
如上面的Github问题所述,第一个SO解决方案存在以下问题.
- 将鼠标光标悬停在按钮上会弹出菜单.但是如果你点击按钮,它将隐藏并显示菜单.恕我直言,这是一个错误.
- 要隐藏菜单,用户需要单击菜单外部.理想情况下,如果鼠标光标位于 超过400毫秒
的区域(包括按钮,菜单和子菜单)之外,则菜单将被隐藏
.
并且在试图解决上述问题之一但不能正常工作的跨度解决方案中,例如
悬停MatMenuTrigger确实mat-menu按预期打开,但如果用户在不输入的情况下移开鼠标mat-menu,则它不会自动关闭,这是错误的.
同时移动到其中一个级别的两个子菜单也关闭了一级菜单,这不是我想要的,
PS将鼠标从一个打开的菜单移动到下一个兄弟菜单不会打开下一个菜单.我想这可能是难以实现提到这里,但我认为,其中的一些可能实现的吧?
这是一个基本的stackBlitz,它重现了我正在经历的,任何帮助表示赞赏.
Mar*_*hal 17
第一个挑战是,mat-menu当由于覆盖层生成CDK覆盖时,从按钮中窃取焦点z-index...为了解决这个问题,您需要为按钮的样式设置z-index ...
(mouseleave)向按钮添加时,这将停止递归循环.style="z-index:1050"接下来,您需要跟踪levelone和levelTwo菜单的所有进入和离开事件的状态,并将该状态存储在两个组件变量中.
enteredButton = false;
isMatMenuOpen = false;
isMatMenu2Open = false;
Run Code Online (Sandbox Code Playgroud)
接下来为两个菜单级别创建菜单enter和menuLeave方法.通知menuLeave(trigger)检查是否访问了level2,如果为true 则不 执行任何操作.
请注意: menu2Leave()有逻辑允许导航回到第一级但是如果退出另一侧则关闭两个...也在离开关卡时移除按钮焦点.
menuenter() {
this.isMatMenuOpen = true;
if (this.isMatMenu2Open) {
this.isMatMenu2Open = false;
}
}
menuLeave(trigger, button) {
setTimeout(() => {
if (!this.isMatMenu2Open && !this.enteredButton) {
this.isMatMenuOpen = false;
trigger.closeMenu();
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-focused');
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-program-focused');
} else {
this.isMatMenuOpen = false;
}
}, 80)
}
menu2enter() {
this.isMatMenu2Open = true;
}
menu2Leave(trigger1, trigger2, button) {
setTimeout(() => {
if (this.isMatMenu2Open) {
trigger1.closeMenu();
this.isMatMenuOpen = false;
this.isMatMenu2Open = false;
this.enteredButton = false;
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-focused');
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-program-focused');
} else {
this.isMatMenu2Open = false;
trigger2.closeMenu();
}
}, 100)
}
buttonEnter(trigger) {
setTimeout(() => {
if(this.prevButtonTrigger && this.prevButtonTrigger != trigger){
this.prevButtonTrigger.closeMenu();
this.prevButtonTrigger = trigger;
trigger.openMenu();
}
else if (!this.isMatMenuOpen) {
this.enteredButton = true;
this.prevButtonTrigger = trigger
trigger.openMenu()
}
else {
this.enteredButton = true;
this.prevButtonTrigger = trigger
}
})
}
buttonLeave(trigger, button) {
setTimeout(() => {
if (this.enteredButton && !this.isMatMenuOpen) {
trigger.closeMenu();
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-focused');
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-program-focused');
} if (!this.isMatMenuOpen) {
trigger.closeMenu();
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-focused');
this.ren.removeClass(button['_elementRef'].nativeElement, 'cdk-program-focused');
} else {
this.enteredButton = false;
}
}, 100)
}
Run Code Online (Sandbox Code Playgroud)
HTML
下面是如何连接所有.
<ng-container *ngFor="let menuItem of modulesList">
<ng-container *ngIf="!menuItem.children">
<a class="nav-link">
<span class="icon fa" [ngClass]="menuItem.icon"></span>
<span class="text-holder">{{menuItem.label}}</span>
</a>
</ng-container>
<ng-container *ngIf="menuItem.children.length > 0">
<button #button mat-button [matMenuTriggerFor]="levelOne" #levelOneTrigger="matMenuTrigger" (mouseenter)="levelOneTrigger.openMenu()" (mouseleave)="buttonLeave(levelOneTrigger, button)" style="z-index:1050">
<span class="icon fa" [ngClass]="menuItem.icon"></span>
<span>{{menuItem.label}}
<i class="fa fa-chevron-down"></i>
</span>
</button>
<mat-menu #levelOne="matMenu" direction="down" yPosition="below">
<span (mouseenter)="menuenter()" (mouseleave)="menuLeave(levelOneTrigger, button)">
<ng-container *ngFor="let childL1 of menuItem.children">
<li class="p-0" *ngIf="!childL1.children" mat-menu-item>
<a class="nav-link">{{childL1.label}}
<i *ngIf="childL1.icon" [ngClass]="childL1.icon"></i>
</a>
</li>
<ng-container *ngIf="childL1.children && childL1.children.length > 0">
<li mat-menu-item #levelTwoTrigger="matMenuTrigger" [matMenuTriggerFor]="levelTwo">
<span class="icon fa" [ngClass]="childL1.icon"></span>
<span>{{childL1.label}}</span>
</li>
<mat-menu #levelTwo="matMenu">
<span (mouseenter)="menu2enter()" (mouseleave)="menu2Leave(levelOneTrigger,levelTwoTrigger, button)">
<ng-container *ngFor="let childL2 of childL1.children">
<li class="p-0" mat-menu-item>
<a class="nav-link">{{childL2.label}}
<i *ngIf="childL2.icon" [ngClass]="childL2.icon"></i>
</a>
</li>
</ng-container>
</span>
</mat-menu>
</ng-container>
</ng-container>
</span>
</mat-menu>
</ng-container>
</ng-container>
Run Code Online (Sandbox Code Playgroud)
Stackblitz
https://stackblitz.com/edit/mat-nested-menu-yclrmd?embed=1&file=app/nested-menu-example.html
Pie*_*dre 17
这是我为处理自动打开/关闭 mat-menu 编写的组件:
import { Component } from '@angular/core';
@Component({
selector: 'app-auto-open-menu',
template: `
<div class="app-nav-item" [matMenuTriggerFor]="menu" #menuTrigger="matMenuTrigger"
(mouseenter)="mouseEnter(menuTrigger)" (mouseleave)="mouseLeave(menuTrigger)">
<ng-content select="[trigger]"></ng-content>
</div>
<mat-menu #menu="matMenu" [hasBackdrop]="false">
<div (mouseenter)="mouseEnter(menuTrigger)" (mouseleave)="mouseLeave(menuTrigger)">
<ng-content select="[content]"></ng-content>
</div>
</mat-menu>
`
})
export class AutoOpenMenuComponent {
timedOutCloser;
constructor() { }
mouseEnter(trigger) {
if (this.timedOutCloser) {
clearTimeout(this.timedOutCloser);
}
trigger.openMenu();
}
mouseLeave(trigger) {
this.timedOutCloser = setTimeout(() => {
trigger.closeMenu();
}, 50);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以在你的应用程序中使用它:
<app-auto-open-menu>
<div trigger>Auto-open</div>
<div content>
<span mat-menu-item>Foo</span>
<span mat-menu-item>Bar</span>
</div>
</app-auto-open-menu>
Run Code Online (Sandbox Code Playgroud)
Sor*_*ean 14
对我有用的最简单的解决方案添加[hasBackdrop]="false" :
<mat-menu [hasBackdrop]="false">
</mat-menu>
Run Code Online (Sandbox Code Playgroud)
小智 11
你可以通过以下方式做到这一点(这是迄今为止最好的方法):
将“ #locationMenuTrigger="matMenuTrigger ”触发器添加到您的按钮,并在此按钮上添加“ (mouseenter) ”事件:
<button
[matMenuTriggerFor]="locationMenu"
#locationMenuTrigger="matMenuTrigger"
(mouseover)="locationMenuTrigger.openMenu()"
>info</button>
Run Code Online (Sandbox Code Playgroud)
将您的“(mouseleave)”事件放在您放入 mat-menu 的 mat-menu div/span 上,如下所示:
<mat-menu #locationMenu="matMenu" class="location-menu">
<span class="locations" (mouseleave)="closeMenu()">
{{ row | notAvailable: '-' }}
</span>
Run Code Online (Sandbox Code Playgroud)
此解决方案可用作 Marshal 建议的设置 z-index:1050 的替代方法。对于其他修复,您应该查看 Marshal 的回答。
您可以使用
<button [matMenuTriggerFor]="menu" #trigger="matMenuTrigger" (mouseenter)="trigger.openMenu()" (mouseleave)="trigger.closeMenu()"></button>
Run Code Online (Sandbox Code Playgroud)
使用它会创建连续的闪烁循环,但有一个简单的修复方法。
只需要处理一件事,即:
菜单打开时
<div class="cdk-overlay-container"></div>
Run Code Online (Sandbox Code Playgroud)
这个 div 覆盖整个屏幕,通常添加在整个 html 的末尾 /body 标签之前。您的所有菜单都在此容器内生成。(不同版本的类名可能不同)。
只需将其添加到您的 css/scss 样式文件中:
.cdk-overlay-container{
left:200px;
top:200px;
}
.cdk-overlay-connected-position-bounding-box{
top:0 !important;
}
Run Code Online (Sandbox Code Playgroud)
或任何阻止此元素与您的按钮重叠的东西。
我自己试过这个,希望我的回答清楚准确。
这是相同的stackblitz演示,我已经编辑了问题中的 stackblitz 代码。
| 归档时间: |
|
| 查看次数: |
13059 次 |
| 最近记录: |