Angular 11+Mat 11:为mat-table行添加多级子菜单自定义右键菜单
Angular 11 + Angular Material 11 实现Mat-Table行多级右键菜单
1. 定义多级菜单数据结构
在组件TS中定义支持嵌套的菜单数据接口,统一管理菜单层级与操作逻辑:
interface MenuItem { label: string; action?: (rowData: any) => void; children?: MenuItem[]; }
示例菜单数据(可根据业务需求调整):
menuItems: MenuItem[] = [ { label: '编辑行', action: (row) => console.log('执行编辑操作:', row) }, { label: '批量操作', children: [ { label: '导出当前行', action: (row) => console.log('导出行数据:', row) }, { label: '状态管理', children: [ { label: '标记为已处理', action: (row) => console.log('标记行:', row) }, { label: '删除记录', action: (row) => console.log('删除行:', row) } ] } ] } ]; currentRowData: any;
2. 修改HTML模板
在原有mat-table基础上,调整右键菜单结构,通过嵌套mat-menu实现多级菜单:
<!-- Mat-Table 核心结构(保留你的列定义) --> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <ng-container matColumnDef="position"> <th mat-header-cell *matHeaderCellDef> No. </th> <td mat-cell *matCellDef="let element"> {{element.position}} </td> </ng-container> <!-- 替换为你自己的列定义 --> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <!-- 绑定右键点击事件到表格行 --> <tr mat-row *matRowDef="let row; columns: displayedColumns;" (contextmenu)="onRowRightClick($event, row)"></tr> </table> <!-- 右键主菜单容器 --> <mat-menu #contextMenu="matMenu"> <ng-template matMenuContent let-row="row"> <ng-container *ngFor="let item of menuItems"> <!-- 渲染带子菜单的项 --> <ng-container *ngIf="item.children && item.children.length; else singleItem"> <button mat-menu-item [matMenuTriggerFor]="subMenu"> {{item.label}} </button> <mat-menu #subMenu="matMenu"> <ng-template matMenuContent let-row="row"> <ng-container *ngFor="let subItem of item.children"> <ng-container *ngIf="subItem.children && subItem.children.length; else subSingleItem"> <button mat-menu-item [matMenuTriggerFor]="subSubMenu"> {{subItem.label}} </button> <mat-menu #subSubMenu="matMenu"> <ng-template matMenuContent let-row="row"> <button mat-menu-item *ngFor="let subSubItem of subItem.children" (click)="subSubItem.action(row)"> {{subSubItem.label}} </button> </ng-template> </mat-menu> </ng-container> <!-- 渲染二级单菜单 --> <ng-template #subSingleItem> <button mat-menu-item (click)="subItem.action(row)"> {{subItem.label}} </button> </ng-template> </ng-container> </ng-template> </mat-menu> </ng-container> <!-- 渲染一级单菜单 --> <ng-template #singleItem> <button mat-menu-item (click)="item.action(row)"> {{item.label}} </button> </ng-template> </ng-container> </ng-template> </mat-menu>
3. 完善TS逻辑
处理右键点击事件,传递行数据并控制菜单显示位置:
import { Component, ViewChild } from '@angular/core'; import { MatMenu } from '@angular/material/menu'; @Component({ selector: 'app-table-contextmenu', templateUrl: './table-contextmenu.component.html', styleUrls: ['./table-contextmenu.component.css'] }) export class TableContextmenuComponent { // 保留你的表格数据与列定义 displayedColumns: string[] = ['position', 'name', 'weight', 'symbol']; dataSource = ELEMENT_DATA; @ViewChild('contextMenu') contextMenu: MatMenu; menuItems: MenuItem[] = [...]; // 上述定义的菜单数据 currentRowData: any; onRowRightClick(event: MouseEvent, row: any) { event.preventDefault(); // 屏蔽浏览器默认右键菜单 this.currentRowData = row; // 在鼠标点击位置打开菜单 this.contextMenu.openMenu({ x: event.clientX, y: event.clientY }); } } // 模拟表格数据(替换为你的业务数据) const ELEMENT_DATA = [ {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H'}, {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'}, {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'} ]; interface MenuItem { label: string; action?: (rowData: any) => void; children?: MenuItem[]; }
核心逻辑说明
- 嵌套菜单触发:通过
[matMenuTriggerFor]将父菜单项与子菜单容器绑定,点击父项自动展开子菜单。 - 行数据传递:利用
matMenuContent的let-row语法,将当前行数据传递至所有层级的菜单项,确保操作能精准关联目标行。 - 右键事件控制:监听行的
contextmenu事件,调用preventDefault()取消浏览器默认菜单,再通过openMenu()在鼠标位置打开自定义菜单。 - 无限层级扩展:若需支持更多层级,可将子菜单渲染逻辑封装为独立组件,通过递归调用减少模板冗余,提升代码可维护性。
内容的提问来源于stack exchange,提问作者pacocom
相关产品推荐
相关产品推荐

