Angular如何不使用私有属性获取MatMenu的ElementRef?
可行方案(全部基于官方公开API,无版本兼容风险)
方案1:新增辅助标记指令获取菜单ElementRef,同时保留触发器操作权限
你可以新增一个仅用于提取菜单ElementRef的空指令,通过模板变量传递给绑定在触发器上的test指令即可同时满足两个需求:
- 定义辅助指令
import { Directive, ElementRef } from '@angular/core'; @Directive({ selector: '[menuRefMarker]', exportAs: 'menuRefMarker' }) export class MenuRefMarker { constructor(public elementRef: ElementRef<HTMLElement>) {} }
- 修改模板关联引用
<!-- test指令绑定在触发器上,保留open/close等操作能力 --> <a [matMenuTriggerFor]="aMenu" test [targetMenuRef]="aMenuMarker"></a> <!-- 给mat-menu绑定辅助指令,导出为模板变量 --> <mat-menu #aMenu menuRefMarker #aMenuMarker="menuRefMarker"></mat-menu>
- 修改test指令接收引用
import { Directive, ElementRef, Input, OnInit } from '@angular/core'; import { MatMenuTrigger } from '@angular/material/menu'; import { MenuRefMarker } from './menu-ref-marker.directive'; @Directive({ selector: '[test]' }) export class Test { @Input() targetMenuRef: MenuRefMarker; constructor( private hostRef: ElementRef, private host: MatMenuTrigger, ) {} ngOnInit() { this.host.menuOpened.subscribe(() => { // 直接拿到菜单的ElementRef,完全基于公开API const menuElementRef = this.targetMenuRef.elementRef; // 你的点击检测逻辑 }); } }
方案2:通过Overlay公开属性直接查询菜单元素
如果不想新增额外指令,可以利用MatMenuTrigger公开的overlayRef属性,在菜单打开后直接查询DOM获取菜单元素:
this.host.menuOpened.subscribe(() => { // .mat-menu-panel是Angular Material官方公开的菜单面板固定类名,跨版本稳定 const menuElement = this.host.overlayRef.overlayElement.querySelector('.mat-menu-panel'); const menuElementRef = new ElementRef(menuElement); // 后续业务逻辑 });
无需访问MatMenuTrigger关闭菜单的方法
如果你将指令绑定在mat-menu标签上,可以通过注入MAT_MENU_TRIGGER令牌获取当前菜单关联的触发器实例,直接调用关闭方法:
import { Directive, ElementRef, Inject, OnInit } from '@angular/core'; import { MAT_MENU_TRIGGER, MatMenuTrigger } from '@angular/material/menu'; @Directive({ selector: '[testOnMenu]' }) export class TestOnMenuDirective implements OnInit { constructor( private menuElementRef: ElementRef, @Inject(MAT_MENU_TRIGGER) private trigger: MatMenuTrigger ) {} ngOnInit() { // 可直接调用触发器的关闭/打开方法 // this.trigger.closeMenu(); } }
针对你的点击检测场景的简化方案
你不需要自己实现composedPath判断逻辑,MatMenuTrigger的overlayRef自带外部点击事件监听:
this.host.menuOpened.subscribe(() => { this.host.overlayRef.outsidePointerEvents().subscribe((event) => { // 这里的event就是菜单外部的点击事件,直接处理你的业务逻辑即可 }); });
内容的提问来源于stack exchange,提问作者Sadiinso
相关产品推荐
相关产品推荐

