You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:47:17