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

如何为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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 09:20:22