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

Angular 14+ 用户详情Mat Data Table弹窗与导出功能实现需求

Angular 14+ Mat Data Table 功能实现方案

前置准备

  1. 确保已导入Angular Material的MatDialogModule到你的模块中
  2. 安装导出依赖:
npm install xlsx papaparse

1. 模板修改(完整代码)

替换原有的mat-card内容,添加导出按钮、修改操作列点击事件、行点击事件:

<mat-card>
  <!-- 导出按钮组 -->
  <div class="d-flex justify-content-end mb-2">
    <button mat-raised-button color="primary" (click)="exportToExcel()">
      导出Excel
    </button>
    <button mat-raised-button color="accent" class="ms-2" (click)="exportToCSV()">
      导出CSV
    </button>
  </div>

  <mat-form-field class="full-width py-2">
    <input class="mt-1"
           matInput
           (keyup)="applyFilter($event)"
           placeholder="Search"
           #input
    />
  </mat-form-field>

  <table mat-table [dataSource]="dataSource" class="mat-elevation-z8" matSort
         #empTbSort="matSort">

    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef mat-sort-header >No.</th>
      <td mat-cell *matCellDef="let element">{{ element.id }}</td>
    </ng-container>

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef mat-sort-header > Name </th>
      <td mat-cell *matCellDef="let element"> {{element.name}} </td>
    </ng-container>

    <ng-container matColumnDef="email">
      <th mat-header-cell *matHeaderCellDef mat-sort-header > email </th>
      <td mat-cell *matCellDef="let element"> {{element.email}} </td>
    </ng-container>

    <ng-container matColumnDef="phone">
      <th mat-header-cell *matHeaderCellDef mat-sort-header > phone </th>
      <td mat-cell *matCellDef="let element"> {{element.phone}} </td>
    </ng-container>

    <ng-container matColumnDef="company">
      <th mat-header-cell *matHeaderCellDef mat-sort-header > company </th>
      <td mat-cell *matCellDef="let element"> {{element.company}} </td>
    </ng-container>

    <ng-container matColumnDef="actions">
      <th mat-header-cell *matHeaderCellDef> actions </th>
      <td mat-cell *matCellDef="let element">
        <button mat-button (click)="openSubordinateDialog(element)">Click here</button>
      </td>
    </ng-container>

    <ng-container matColumnDef="role">
      <mat-header-cell *matHeaderCellDef> Role Name </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.role}} </mat-cell>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef ="displayedColumns"></tr>
    <tr (click)="openUserDetailDialog(emprow)" mat-row *matRowDef="let emprow; columns: displayedColumns"></tr>

  </table>
  <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
</mat-card>

2. 主组件逻辑(.ts文件)

import { Component, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { MatDialog } from '@angular/material/dialog';
import * as XLSX from 'xlsx';
import * as Papa from 'papaparse';

// 导入自定义弹窗组件(需要你自己创建)
import { SubordinateDialogComponent } from './subordinate-dialog/subordinate-dialog.component';
import { UserDetailDialogComponent } from './user-detail-dialog/user-detail-dialog.component';

// 定义用户数据接口
export interface User {
  id: number;
  name: string;
  email: string;
  phone: string;
  company: string;
  role: string;
  // 额外信息字段
  address?: string;
  website?: string;
  // 下属数据字段
  subordinates?: { id: number; name: string; department: string }[];
}

@Component({
  selector: 'app-user-table',
  templateUrl: './user-table.component.html',
  styleUrls: ['./user-table.component.scss']
})
export class UserTableComponent {
  displayedColumns: string[] = ['id', 'name', 'email', 'phone', 'company', 'role', 'actions'];
  dataSource: MatTableDataSource<User>;

  @ViewChild(MatSort) sort!: MatSort;
  @ViewChild(MatPaginator) paginator!: MatPaginator;

  // 模拟数据,实际替换为你的接口数据
  users: User[] = [
    {
      id: 1,
      name: 'John Doe',
      email: 'john@example.com',
      phone: '123-456-7890',
      company: 'Tech Corp',
      role: 'Manager',
      address: '123 Main St, City',
      website: 'example.com',
      subordinates: [
        { id: 101, name: 'Jane Smith', department: 'Dev' },
        { id: 102, name: 'Bob Brown', department: 'Design' }
      ]
    },
    // 更多用户数据...
  ];

  constructor(private dialog: MatDialog) {
    this.dataSource = new MatTableDataSource(this.users);
  }

  ngAfterViewInit() {
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource.filter = filterValue.trim().toLowerCase();
  }

  // 功能1:打开下属弹窗
  openSubordinateDialog(user: User) {
    this.dialog.open(SubordinateDialogComponent, {
      width: '500px',
      data: user.subordinates || []
    });
  }

  // 功能2:导出Excel
  exportToExcel() {
    const worksheet = XLSX.utils.json_to_sheet(this.dataSource.data);
    const workbook = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(workbook, worksheet, 'Users');
    XLSX.writeFile(workbook, 'user-data.xlsx');
  }

  // 功能2:导出CSV
  exportToCSV() {
    const csv = Papa.unparse(this.dataSource.data);
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'user-data.csv');
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }

  // 功能3:打开用户详情弹窗
  openUserDetailDialog(user: User) {
    this.dialog.open(UserDetailDialogComponent, {
      width: '600px',
      data: user
    });
  }
}

3. 弹窗组件实现

下属弹窗组件(subordinate-dialog.component.ts)

import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';

export interface Subordinate {
  id: number;
  name: string;
  department: string;
}

@Component({
  selector: 'app-subordinate-dialog',
  templateUrl: './subordinate-dialog.component.html',
})
export class SubordinateDialogComponent {
  constructor(@Inject(MAT_DIALOG_DATA) public data: Subordinate[]) {}
}

对应的HTML:

<h2 mat-dialog-title>下属信息</h2>
<mat-dialog-content>
  <table mat-table [dataSource]="data" class="mat-elevation-z2">
    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef>ID</th>
      <td mat-cell *matCellDef="let element">{{element.id}}</td>
    </ng-container>
    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef>姓名</th>
      <td mat-cell *matCellDef="let element">{{element.name}}</td>
    </ng-container>
    <ng-container matColumnDef="department">
      <th mat-header-cell *matHeaderCellDef>部门</th>
      <td mat-cell *matCellDef="let element">{{element.department}}</td>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="['id', 'name', 'department']"></tr>
    <tr mat-row *matRowDef="let row; columns: ['id', 'name', 'department']"></tr>
  </table>
</mat-dialog-content>
<mat-dialog-actions>
  <button mat-button mat-dialog-close>关闭</button>
</mat-dialog-actions>

用户详情弹窗组件(user-detail-dialog.component.ts)

import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { User } from '../user-table/user-table.component';

@Component({
  selector: 'app-user-detail-dialog',
  templateUrl: './user-detail-dialog.component.html',
})
export class UserDetailDialogComponent {
  constructor(@Inject(MAT_DIALOG_DATA) public data: User) {}
}

对应的HTML:

<h2 mat-dialog-title>{{data.name}} 详情</h2>
<mat-dialog-content class="mat-typography">
  <div class="detail-item">
    <span class="label">邮箱:</span>{{data.email}}
  </div>
  <div class="detail-item">
    <span class="label">电话:</span>{{data.phone}}
  </div>
  <div class="detail-item">
    <span class="label">公司地址:</span>{{data.company}} - {{data.address}}
  </div>
  <div class="detail-item">
    <span class="label">网站:</span>{{data.website}}
  </div>
</mat-dialog-content>
<mat-dialog-actions>
  <button mat-button mat-dialog-close>关闭</button>
</mat-dialog-actions>

添加基础样式(可选):

.detail-item {
  margin: 10px 0;
  .label {
    font-weight: bold;
    margin-right: 8px;
  }
}

4. 模块配置

确保在你的模块中导入并声明相关组件:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatTableModule } from '@angular/material/table';
import { MatSortModule } from '@angular/material/sort';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { UserTableComponent } from './user-table/user-table.component';
import { SubordinateDialogComponent } from './subordinate-dialog/subordinate-dialog.component';
import { UserDetailDialogComponent } from './user-detail-dialog/user-detail-dialog.component';

@NgModule({
  declarations: [
    UserTableComponent,
    SubordinateDialogComponent,
    UserDetailDialogComponent
  ],
  imports: [
    CommonModule,
    MatTableModule,
    MatSortModule,
    MatPaginatorModule,
    MatFormFieldModule,
    MatInputModule,
    MatButtonModule,
    MatDialogModule
  ],
  exports: [UserTableComponent]
})
export class UserTableModule { }

内容的提问来源于stack exchange,提问作者Vijay Dhumale

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:49:59