Angular Material 16悬浮菜单mouseleave事件异常触发求助
Angular Material 16 悬浮菜单mouseleave事件异常问题
我在使用Angular Material 16开发鼠标悬浮触发的菜单时,遇到了异常问题:鼠标刚进入按钮,mouseleave事件就被触发,导致菜单刚显示就立刻关闭。在buttonLeave方法中设置断点后,确认鼠标一进入按钮该方法就被调用,完全不符合“鼠标离开按钮时触发”的预期。
组件模板代码
<ng-container *ngFor="let menuItem of menuList"> <ng-container *ngIf="!menuItem.children"> <button class="nav-link" [routerLink]="menuItem.link" style="z-index: 1050;" > <span class="icon fa" [ngClass]="menuItem.icon"></span> <span class="text-holder">{{ menuItem.label }}</span> </button> </ng-container> <ng-container *ngIf="menuItem.children && menuItem.children.length > 0"> <button #button mat-button [matMenuTriggerFor]="levelOne" #levelOneTrigger="matMenuTrigger" (mouseenter)="buttonEnter(levelOneTrigger)" (mouseleave)="buttonLeave(levelOneTrigger, button)" style="z-index:2000" > <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" class="mnred1" > <span (mouseenter)="menuenter()" (mouseleave)="menuLeave(levelOneTrigger, button)" class="mnred2" > <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>
问题原因
核心问题出在MatMenu的渲染逻辑对鼠标事件的干扰:
- 当
mouseenter触发按钮打开菜单后,MatMenu会立即在按钮附近渲染菜单DOM,这个过程可能导致按钮元素发生微小的布局偏移,或者菜单元素覆盖了按钮的部分区域,让浏览器误判鼠标已经离开按钮,从而触发mouseleave事件。 - 手动给按钮设置的
z-index:2000打破了MatMenu默认的层级管理,菜单渲染时的层级冲突进一步干扰了鼠标事件的判定。
修复方案
1. 改用延迟关闭逻辑,避免误触发
通过跟踪鼠标是否在按钮或菜单区域,结合延迟判断来关闭菜单,减少误判:
- 在组件类中添加状态变量:
isMouseInButton = false; isMouseInLevelOneMenu = false; isMouseInLevelTwoMenu = false;
- 修改模板中的事件绑定:
<button #button mat-button [matMenuTriggerFor]="levelOne" #levelOneTrigger="matMenuTrigger" (mouseenter)="isMouseInButton = true; levelOneTrigger.openMenu()" (mouseleave)="isMouseInButton = false; closeLevelOneMenuDelayed(levelOneTrigger)" > <!-- 按钮原有内容 --> </button> <mat-menu #levelOne="matMenu" direction="down" yPosition="below" class="mnred1"> <span (mouseenter)="isMouseInLevelOneMenu = true" (mouseleave)="isMouseInLevelOneMenu = false; closeLevelOneMenuDelayed(levelOneTrigger)" class="mnred2" > <!-- 一级菜单原有内容 --> <mat-menu #levelTwo="matMenu"> <span (mouseenter)="isMouseInLevelTwoMenu = true" (mouseleave)="isMouseInLevelTwoMenu = false; closeLevelTwoMenuDelayed(levelOneTrigger, levelTwoTrigger)" > <!-- 二级菜单原有内容 --> </span> </mat-menu> </span> </mat-menu>
- 添加延迟关闭方法:
closeLevelOneMenuDelayed(trigger: MatMenuTrigger) { setTimeout(() => { if (!this.isMouseInButton && !this.isMouseInLevelOneMenu && !this.isMouseInLevelTwoMenu) { trigger.closeMenu(); } }, 200); } closeLevelTwoMenuDelayed(levelOneTrigger: MatMenuTrigger, levelTwoTrigger: MatMenuTrigger) { setTimeout(() => { if (!this.isMouseInLevelOneMenu && !this.isMouseInLevelTwoMenu) { levelTwoTrigger.closeMenu(); } if (!this.isMouseInButton && !this.isMouseInLevelOneMenu && !this.isMouseInLevelTwoMenu) { levelOneTrigger.closeMenu(); } }, 200); }
2. 移除手动设置的z-index
删除按钮上的style="z-index:2000",让MatMenu自行管理菜单和按钮的层级关系,避免布局冲突。
3. 禁用菜单背景遮罩(可选)
如果不需要菜单的背景遮罩,可以给mat-menu添加[hasBackdrop]="false",减少背景元素对鼠标事件的干扰:
<mat-menu #levelOne="matMenu" direction="down" yPosition="below" class="mnred1" [hasBackdrop]="false">
内容的提问来源于stack exchange,提问作者HDJEMAI
相关产品推荐
相关产品推荐

