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

如何为Angular Material 14日期范围选择器添加输入掩码

Angular Material 14日期范围选择器实现手动输入自动掩码(dd/mm/YYYY)

解决方案:自定义输入掩码指令

Angular Material 14本身没有内置日期输入掩码功能,最可靠的方式是编写自定义指令处理输入格式化,同时限制仅允许数字输入。

步骤1:创建日期掩码指令

新建date-mask.directive.ts文件,实现输入时自动插入/分隔符并过滤非数字字符:

import { Directive, HostListener, ElementRef } from '@angular/core';

@Directive({
  selector: '[appDateMask]'
})
export class DateMaskDirective {
  constructor(private el: ElementRef) {}

  // 实时监听输入并格式化
  @HostListener('input', ['$event']) onInput(event: KeyboardEvent) {
    const input = this.el.nativeElement;
    // 移除所有非数字字符
    let cleanValue = input.value.replace(/\D/g, '');
    let formattedValue = '';

    // 按dd/mm/yyyy规则拼接内容
    if (cleanValue.length > 0) {
      formattedValue += cleanValue.substring(0, 2);
      if (cleanValue.length > 2) {
        formattedValue += '/' + cleanValue.substring(2, 4);
        if (cleanValue.length > 4) {
          formattedValue += '/' + cleanValue.substring(4, 8); // 限制年份最多4位
        }
      }
    }

    input.value = formattedValue;
    event.preventDefault();
  }

  // 失去焦点时补充分隔符或修正格式
  @HostListener('blur') onBlur() {
    const input = this.el.nativeElement;
    const cleanValue = input.value.replace(/\D/g, '');
    
    switch (cleanValue.length) {
      case 2:
        input.value = `${cleanValue}/`;
        break;
      case 4:
        input.value = `${cleanValue.substring(0,2)}/${cleanValue.substring(2,4)}/`;
        break;
      case 6:
      case 7:
      case 8:
        input.value = `${cleanValue.substring(0,2)}/${cleanValue.substring(2,4)}/${cleanValue.substring(4,8)}`;
        break;
      default:
        // 输入长度不足时可选择清空或保留现有内容
        break;
    }
  }
}

步骤2:在模块中注册指令

在根模块(如AppModule)中声明并导出该指令:

import { DateMaskDirective } from './date-mask.directive';

@NgModule({
  declarations: [
    // ...其他组件/指令
    DateMaskDirective
  ],
  exports: [
    // 若需在其他模块使用,导出指令
    DateMaskDirective
  ]
})
export class AppModule { }

步骤3:在模板中应用指令

给日期范围选择器的输入框添加appDateMask指令:

<mat-form-field appearance="fill">
  <mat-date-range-input [rangePicker]="picker" [max]="today">
    <input matStartDate [(ngModel)]="item.startValue" [placeholder]="'Of' | translate" 
           #dateRangeStart appDateMask (keypress)="validation($event, index)">
    <input matEndDate [(ngModel)]="item.endValue" [placeholder]="'Till' | translate" 
           #dateRangeEnd appDateMask (dateChange)="dateRangeChange(index)" (keypress)="validation($event, index)">
  </mat-date-range-input>
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <mat-date-range-picker #picker (closed)="afterClose(item, index)"></mat-date-range-picker>
</mat-form-field>

优化输入验证逻辑

修改原validation方法,仅允许数字输入,并增加日期合法性校验:

validation(event: KeyboardEvent, index: number) {
  // 仅允许数字和退格键输入
  const charCode = event.which || event.keyCode;
  if (charCode !== 8 && (charCode < 48 || charCode > 57)) {
    event.preventDefault();
    return false;
  }

  if (this.filterList[index].validation) {
    if (this.filterList[index].type === 'date') {
      // 校验日期格式合法性(dd/mm/yyyy)
      const dateStr = this.filterList[index].startValue;
      const dateParts = dateStr.split('/');
      if (dateParts.length === 3) {
        const day = parseInt(dateParts[0], 10);
        const month = parseInt(dateParts[1], 10);
        const year = parseInt(dateParts[2], 10);
        // 验证日期是否有效
        const validDate = new Date(year, month - 1, day);
        if (validDate.getDate() !== day || validDate.getMonth() + 1 !== month || validDate.getFullYear() !== year) {
          return { date: true };
        }
      }
    }
    // 保留原有validation逻辑
    if (eval(this.filterList[index].validation)) {
      return true;
    }
    return false;
  }
}

统一日期格式(选择器与手动输入)

日期选择器返回的是Date对象,手动输入的是字符串,需统一格式。在dateChange和afterClose方法中转换:

dateRangeChange(index: number) {
  // 将选择器返回的Date对象转为dd/mm/yyyy字符串
  if (this.item.endValue instanceof Date) {
    const day = this.item.endValue.getDate().toString().padStart(2, '0');
    const month = (this.item.endValue.getMonth() + 1).toString().padStart(2, '0');
    const year = this.item.endValue.getFullYear();
    this.item.endValue = `${day}/${month}/${year}`;
  }
  // 原有的业务逻辑
}

afterClose(item: any, index: number) {
  // 处理起始日期
  if (item.startValue instanceof Date) {
    const day = item.startValue.getDate().toString().padStart(2, '0');
    const month = (item.startValue.getMonth() + 1).toString().padStart(2, '0');
    const year = item.startValue.getFullYear();
    item.startValue = `${day}/${month}/${year}`;
  }
  // 处理结束日期
  if (item.endValue instanceof Date) {
    const day = item.endValue.getDate().toString().padStart(2, '0');
    const month = (item.endValue.getMonth() + 1).toString().padStart(2, '0');
    const year = item.endValue.getFullYear();
    item.endValue = `${day}/${month}/${year}`;
  }
  // 原有的业务逻辑
}

内容的提问来源于stack exchange,提问作者John Doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:10:32