如何为Angular Material表格单元格实现类条形图的部分背景填充
问题描述
我需要为Angular Material表格的单元格设置背景填充,使其根据单元格数值呈现类似条形图的效果。参考了「基于百分比设置div背景色(如进度条)」的方案,但目前填充div的高度仅与字体高度一致,无法铺满单元格。当前使用静态宽度进行测试,后续会改为单元格对应数值,且条形从中间起始(因部分列可能为负值)。希望实现以下两种方案之一:让div高度适配父单元格,或直接为单元格应用该填充效果(优先选择后者)。
当前代码
HTML
<ng-container *transloco="let t; read: 'dashboard'"> <div class="card-container"> <!-- other cards --> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns"> <th mat-header-cell *matHeaderCellDef> {{column}} </th> <td mat-cell *matCellDef="let element"> <div class="progressbar-wrapper"> {{element[column]}} <div class="progressbar" style="width: 28%"></div> <div class="progressbar2" style="width: 28%"></div> </div> </td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> </div> </ng-container>
CSS
.card-container { width: 85vw; height: 90vh; display: flex; flex-wrap: wrap; flex-direction: column; justify-content: space-evenly; } .overview-card { width: 40%; height: fit-content; /* height: 46%; */ } .overview-content { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-between; } .overview-item { margin: 10px; margin-top: 0px; } .make-gold { background-color: gold } .progressbar-wrapper { position: relative; z-index: 1; } .progressbar { position: absolute; top: 0; bottom: 0; left: 50%; background-color: #dcf3dd; z-index: -1; } .progressbar2 { position: absolute; top: 0; bottom: 0; left: 22%; background-color: #1ccb25; z-index: -1; } .table-card { width: 44%; height: 46%; } .value-card { width: 20%; height: 20%; }
TypeScript
import { Component, OnInit } from "@angular/core"; import { MatTableDataSource } from "@angular/material/table"; @Component({ selector: "app-dashboard-page", templateUrl: "./dashboard-page.component.html", styleUrls: ["./dashboard-page.component.scss"], }) export class DashboardPageComponent implements OnInit { displayedColumns: string[] = ["name", "status", "windDirection", "windSpeed", "power"]; dataSource = new MatTableDataSource(ELEMENT_DATA); constructor() {} ngOnInit(): void {} } export interface PeriodicElement { name: string; status: string; windDirection: number; windSpeed: number; power: number; } const ELEMENT_DATA: PeriodicElement[] = [ { name: "Hydrogen", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Helium", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Lithium", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Beryllium", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Boron", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Carbon", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Nitrogen", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Oxygen", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, { name: "Fluorine", status: "ok", windDirection: 180.0, power: 900, }, { name: "Neon", status: "ok", windDirection: 180.0, windSpeed: 8.2, power: 900, }, ];
解决方案
方案一:让填充div铺满单元格
通过设置父容器高度继承,确保填充div能铺满整个单元格:
/* 让单元格高度被正确继承 */ mat-cell { height: 100%; padding: 16px 0; /* 保留Material表格默认内边距 */ } .progressbar-wrapper { position: relative; z-index: 1; height: 100%; display: flex; align-items: center; /* 让文字垂直居中 */ padding: 0 16px; /* 对应单元格水平内边距 */ }
方案二:直接为单元格应用填充效果(优先推荐)
无需嵌套额外div,利用单元格伪元素或动态绑定样式实现,更简洁且自动适配单元格高度:
1. 修改HTML结构
去掉嵌套的进度条容器,直接显示数值:
<td mat-cell *matCellDef="let element" [class.cell-with-bar]="column !== 'name' && column !== 'status'"> <span class="cell-text">{{element[column]}}</span> <span class="bar-bg" [style.width.%]="getBarWidth(element[column], column)" [style.left.%]="element[column] >= 0 ? 50 : null" [style.right.%]="element[column] < 0 ? 50 : null" [class.negative-bar]="element[column] < 0"></span> </td>
2. 添加CSS样式
mat-cell.cell-with-bar { position: relative; overflow: hidden; } .cell-text { position: relative; z-index: 1; display: block; padding: 16px; } .bar-bg { position: absolute; top: 0; bottom: 0; background-color: #dcf3dd; z-index: 0; } .bar-bg.negative-bar { background-color: #f8d7da; /* 负值用红色背景区分 */ }
3. TypeScript中添加动态计算逻辑
计算每列的最大值,用于生成百分比宽度:
columnMaxValues: {[key: string]: number} = {}; ngOnInit(): void { // 计算各数值列的绝对值最大值 this.displayedColumns.forEach(col => { if (col !== 'name' && col !== 'status') { this.columnMaxValues[col] = Math.max(...this.dataSource.data.map(item => Math.abs(item[col]))); } }); } // 计算条形宽度百分比 getBarWidth(value: number, column: string): number { const maxVal = this.columnMaxValues[column]; return maxVal ? (Math.abs(value) / maxVal) * 100 : 0; }
内容的提问来源于stack exchange,提问作者JWo
相关产品推荐
相关产品推荐

