Angular技术问题:键盘焦点移出mat-menu菜单项时如何关闭菜单
实现思路
通过监听全局焦点变化,判断当前焦点是否处于mat-menu内部或触发菜单的按钮上,若都不在且菜单处于打开状态,则调用菜单的关闭方法。
具体实现步骤
1. 获取MatMenu实例与触发按钮元素
用@ViewChild装饰器获取mat-menu的实例,同时给触发菜单的按钮添加模板引用变量,用于后续判断焦点归属。
2. 监听全局焦点事件
通过@HostListener监听document的focus事件,在回调中检查焦点元素:
- 若焦点不在菜单内部,也不在触发按钮上
- 且菜单当前处于打开状态
- 则调用菜单的
close()方法完成关闭
3. 代码示例
组件类代码
import { Component, ViewChild, ElementRef, HostListener } from '@angular/core'; import { MatMenu } from '@angular/material/menu'; @Component({ selector: 'app-menu-icons-example', templateUrl: './menu-icons-example.html', }) export class MenuIconsExample { @ViewChild('menu') menu!: MatMenu; @ViewChild('triggerBtn') triggerBtn!: ElementRef<HTMLButtonElement>; @HostListener('document:focus', ['$event.target']) onDocumentFocus(targetElement: HTMLElement) { // 菜单未打开时跳过处理 if (!this.menu.menuOpen) return; // 判断焦点是否在菜单内部或触发按钮上 const isInMenu = this.menu.menuElement.nativeElement.contains(targetElement); const isOnTriggerBtn = this.triggerBtn.nativeElement === targetElement; // 焦点不在目标区域则关闭菜单 if (!isInMenu && !isOnTriggerBtn) { this.menu.close(); } } }
模板代码
<button #triggerBtn mat-button [matMenuTriggerFor]="menu">Menu</button> <mat-menu #menu="matMenu"> <button mat-menu-item>Item 1</button> <button mat-menu-item>Item 2</button> <button mat-menu-item>Item 3</button> </mat-menu>
补充说明
- 该方案同时支持键盘Tab切换焦点到菜单外、鼠标点击菜单外两种场景
- 通过
menuElement判断焦点是否在菜单内部,覆盖所有菜单项及菜单容器 - 加入菜单打开状态判断,避免无意义的重复关闭操作
内容的提问来源于stack exchange,提问作者Explorer
相关产品推荐
相关产品推荐

