Angular Material matDatepicker手动输入日期失焦后值错误问题
问题根因
- 核心错误是自定义
CustomDateAdapter的解析逻辑写反了月、日位置。你页面提示输入格式为MM/DD/YYYY,按/分割字符串后,索引0对应月份、索引1对应日期、索引2对应年份,但现有代码把索引1的值减1作为月份、索引0的值作为日期,从根源上解析错位。
以你测试的输入5/24/2022为例,分割后得到数组['5','24','2022'],按现有逻辑计算月份为24-1=23、日期为5,JS Date构造函数会自动对超范围的月份做进位换算,本身就会产生日期偏移,再叠加配置错误就得到了你看到的错误日期值。 - 日期格式配置存在两个问题:一是注入token错误,你写的
NGX_MAT_DATE_FORMATS是第三方ngx日期时间组件的注入标识,如果你用的是Angular Material官方的MatDatepicker,这个配置完全不会生效,组件会走默认解析逻辑二次覆写输入值;二是纯日期选择器不需要配置hour、minute、hourCycle这类时间字段,会干扰组件的解析判断。 - 日期变更事件里多余的日期转换会放大错误:
dateChange事件返回的event.value本身就是DateAdapter解析完成的Date对象,你再手动执行new Date(event.value)属于重复操作,极端场景下还会触发时区偏移问题。
修复方案
- 修正
CustomDateAdapter的解析逻辑,对齐MM/DD/YYYY格式,补充基础合法性校验
export class CustomDateAdapter extends NativeDateAdapter { parse(value: any): Date | null { if ((typeof value === 'string') && (value.indexOf('/') > -1)) { const str = value.split('/'); // 过滤格式不合法的输入 if (str.length !== 3) return null; const year = Number(str[2]); // 索引0为月份,转0基准值需要减1 const month = Number(str[0]) - 1; // 索引1为日期 const date = Number(str[1]); // 过滤非数字的非法输入 if (isNaN(year) || isNaN(month) || isNaN(date)) return null; return new Date(year, month, date); } // 兼容Date对象、时间戳传值场景 if (value instanceof Date) return value; const timestamp = typeof value === 'number' ? value : Date.parse(value); return isNaN(timestamp) ? null : new Date(timestamp); } getFirstDayOfWeek(): number { return 1; } }
- 修正日期格式配置,替换为正确的注入token,移除冗余的时间字段
// 从@angular/material/core导入MAT_DATE_FORMATS,不要用ngx的token const MAT_DATE_FORMATS = { parse: { dateInput: 'MM/DD/YYYY', }, display: { dateInput: 'MM/DD/YYYY', monthYearLabel: { year: 'numeric', month: 'short' }, dateA11yLabel: { year: 'numeric', month: 'long', day: 'numeric' }, monthYearA11yLabel: { year: 'numeric', month: 'long' }, }, }; // 模块providers配置 providers: [ { provide: MAT_DATE_FORMATS, useValue: MAT_DATE_FORMATS }, { provide: DateAdapter, useClass: CustomDateAdapter }, ]
注意:如果项目中同时引入了ngx-mat-datetime-picker类的第三方日期库,检查模块导入顺序,避免第三方库的provider覆盖你自定义的配置。
3. 简化日期变更事件逻辑,移除重复的Date构造
// 记得从@angular/material/datepicker导入MatDatepickerInputEvent类型 onStartDateChange(event: MatDatepickerInputEvent<Date>) { if (!event.value) { this.startDate.setValue(null); return; } // event.value已经是解析完成的合法Date对象,直接赋值给响应式表单控件即可 this.startDate.setValue(event.value); }
验证结果
修复完成后,手动输入5/24/2022失焦、切换字段时,组件会正确解析为2022年5月24日,日历面板选值、表单校验逻辑均保持正常。
内容的提问来源于stack exchange,提问作者gjonte
相关产品推荐
相关产品推荐

