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

为Angular mat-stepper实现字段填充关联的进度条显示

实现Angular Material Stepper自定义动态进度条替换默认水平线

当然可行!我之前做项目的时候刚好实现过类似的需求,核心思路是先隐藏掉mat-horizontal-stepper自带的分隔线,然后自定义一个进度条组件,再结合每个步骤内表单字段的填写状态来动态计算进度值。下面是具体的实现步骤:


1. 隐藏默认的水平线和步骤连接线

Angular Material的步进器自带了默认的分隔线和步骤间的连接线,我们可以通过CSS来隐藏它们:

/* 隐藏步进器头部的底部水平线 */
::ng-deep .mat-horizontal-stepper-header-container {
  border-bottom: none !important;
}

/* 隐藏步骤之间的连接线 */
::ng-deep .mat-horizontal-stepper .mat-stepper-horizontal-line {
  display: none !important;
}

注意:如果你的样式是写在全局样式文件(比如styles.css)里,可以去掉::ng-deep,避免样式穿透的问题。


2. 添加自定义进度条

在mat-horizontal-stepper的上方或下方添加Angular Material的进度条组件mat-progress-bar,绑定进度值:

<!-- 自定义进度条 -->
<mat-progress-bar mode="determinate" [value]="progressValue" color="primary"></mat-progress-bar>

<!-- 你的步进器 -->
<mat-horizontal-stepper [linear]="true" #stepper>
  <mat-step [stepControl]="personalForm">
    <form [formGroup]="personalForm">
      <mat-form-field>
        <input matInput placeholder="姓名" formControlName="name" required>
      </mat-form-field>
      <mat-form-field>
        <input matInput placeholder="邮箱" formControlName="email" required>
      </mat-form-field>
      <button mat-button matStepperNext>下一步</button>
    </form>
  </mat-step>

  <mat-step [stepControl]="addressForm">
    <form [formGroup]="addressForm">
      <mat-form-field>
        <input matInput placeholder="地址" formControlName="address" required>
      </mat-form-field>
      <button mat-button matStepperPrevious>上一步</button>
      <button mat-button matStepperNext>下一步</button>
    </form>
  </mat-step>

  <mat-step>
    <p>所有信息已填写完成!</p>
    <button mat-button matStepperPrevious>上一步</button>
    <button mat-button (click)="submit()">提交</button>
  </mat-step>
</mat-horizontal-stepper>

3. 实现动态进度计算逻辑

接下来在组件类中编写逻辑,监听每个表单字段的变化,计算已填写的必填字段比例,从而更新进度条的值:

import { Component, ViewChild } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatStepper } from '@angular/material/stepper';

@Component({
  selector: 'app-custom-stepper',
  templateUrl: './custom-stepper.component.html',
  styleUrls: ['./custom-stepper.component.css']
})
export class CustomStepperComponent {
  @ViewChild('stepper') stepper!: MatStepper;
  progressValue = 0;

  // 步骤表单
  personalForm: FormGroup;
  addressForm: FormGroup;

  constructor(private fb: FormBuilder) {
    // 初始化表单
    this.personalForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]]
    });

    this.addressForm = this.fb.group({
      address: ['', Validators.required]
    });

    // 监听表单变化,实时计算进度
    this.setupFormListeners();
  }

  setupFormListeners() {
    // 收集所有步骤的表单
    const allForms = [this.personalForm, this.addressForm];

    // 为每个表单添加值变化监听
    allForms.forEach(form => {
      form.valueChanges.subscribe(() => {
        this.calculateProgress(allForms);
      });
    });

    // 初始化时计算一次进度
    this.calculateProgress(allForms);
  }

  calculateProgress(allForms: FormGroup[]) {
    let filledRequiredFields = 0;
    let totalRequiredFields = 0;

    allForms.forEach(form => {
      // 遍历当前表单的所有控件
      Object.values(form.controls).forEach(control => {
        // 统计必填字段
        if (control.hasValidator(Validators.required)) {
          totalRequiredFields++;
          // 判断字段是否已填写(非空且不为空白字符)
          if (control.value && control.value.trim() !== '') {
            filledRequiredFields++;
          }
        }
      });
    });

    // 计算进度值,确保在0-100之间
    this.progressValue = totalRequiredFields === 0 
      ? 0 
      : Math.min((filledRequiredFields / totalRequiredFields) * 100, 100);
  }

  submit() {
    // 提交逻辑
    console.log('表单提交成功!');
  }
}

可选优化:结合步骤激活状态计算进度

如果希望进度条同时反映步骤的完成状态(比如已完成的步骤占比 + 当前步骤的填写比例),可以调整calculateProgress方法:

calculateProgress(allForms: FormGroup[]) {
  const totalSteps = this.stepper.steps.length;
  const completedSteps = this.stepper._getCompletedIndices().length;
  let currentStepFillRatio = 0;

  // 获取当前激活的步骤表单
  const activeStepIndex = this.stepper.selectedIndex;
  if (activeStepIndex < allForms.length) {
    const currentForm = allForms[activeStepIndex];
    let currentFilled = 0;
    let currentTotal = 0;

    Object.values(currentForm.controls).forEach(control => {
      if (control.hasValidator(Validators.required)) {
        currentTotal++;
        if (control.value && control.value.trim() !== '') {
          currentFilled++;
        }
      }
    });

    currentStepFillRatio = currentTotal === 0 ? 0 : currentFilled / currentTotal;
  }

  // 总进度 = 已完成步骤占比 + 当前步骤填写比例 / 总步骤数
  this.progressValue = ((completedSteps + currentStepFillRatio) / totalSteps) * 100;
}

这样进度条会更贴合用户的操作流程,既体现已完成的步骤,又实时展示当前步骤的填写进度。

内容的提问来源于stack exchange,提问作者sai prasad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:40:28