Angular Material Timepicker 完整实战指南:从基础用法到表单集成、校验与国际化
2026/9/13 2:48:26 网站建设 项目流程

Angular Material Timepicker 完整实战指南:从基础用法到表单集成、校验与国际化

【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components

导读

本文围绕 Angular Material 官方组件库中的 Timepicker(时间选择器)展开,系统讲解如何通过matTimepicker将文本输入框与下拉选项列表组合,让用户既可以手动输入时间,也可以从预置的选项列表中快速选择,且值直接落在 Date 对象的"时间部分"。读完本文,你将掌握 Timepicker 与mat-form-field@angular/formsMatDatepicker的组合用法,能够配置校验规则(matTimepickerMin/matTimepickerMax)、自定义下拉选项间隔、定制图标与多语言环境,并理解其底层基于DateAdapterMAT_DATE_FORMATS的实现机制,足以在实际项目中独立落地一个完整的日期时间选择方案。

Timepicker 是什么

Angular Material 的 Timepicker 允许用户设置 Date 对象的时间部分——既可以手动键入时间,也可以从一组预定义的时间选项中点选。官方文档(timepicker.md)开篇即点明它的定位:它只负责"时间",不负责"日期",因此天然适合与mat-datepicker协作构成完整的日期时间选择器。

从源码看,MatTimepicker组件(timepicker.ts)通过selector: 'mat-timepicker'暴露,底层复用了 CDK 的 Overlay、MatOption列表与ActiveDescendantKeyManager键盘管理,渲染为一个 listbox 样式的下拉面板,并通过opened/closed/selected三个输出事件与外界通信。它由三部分协作组成:

  • mat-timepicker:下拉面板本体,负责生成与渲染时间选项;
  • mat-timepicker-toggle:可选的开合按钮(默认渲染一个时钟图标);
  • 输入框上的matTimepicker绑定:把<input>与 timepicker 面板连接起来。

将 Timepicker 连接到输入框

一个 timepicker 由文本输入框和下拉菜单组成,二者通过输入框上的matTimepicker绑定连接。官方最小化示例(timepicker-overview-example.html)如下:

<mat-form-field> <mat-label>Pick a time</mat-label> <input matInput [matTimepicker]="picker"> <mat-timepicker-toggle matIconSuffix [for]="picker"/> <mat-timepicker #picker/> </mat-form-field>

对应的组件类(timepicker-overview-example.ts)需要显式引入三个模块,并提供一个日期适配器:

import {Component} from '@angular/core'; import {MatTimepickerModule} from '@angular/material/timepicker'; import {MatInputModule} from '@angular/material/input'; import {MatFormFieldModule} from '@angular/material/form-field'; import {provideNativeDateAdapter} from '@angular/material/core'; @Component({ selector: 'timepicker-overview-example', templateUrl: 'timepicker-overview-example.html', providers: [provideNativeDateAdapter()], imports: [MatFormFieldModule, MatInputModule, MatTimepickerModule], }) export class TimepickerOverviewExample {}

需要说明的是,mat-timepicker-toggle上的matIconSuffix指令负责把开关按钮作为后缀嵌入表单字段中,[for]="picker"指明它控制的是哪个 timepicker。官方强调:输入框与开关可以独立使用,也可以作为mat-form-field的一部分——上述示例演示了最常规的 form-field 组合方式。

输入框的行为细节

从 timepicker-input.ts 的源码可以看到输入框的几处关键交互逻辑:

  • 点击输入框打开面板matTimepickerOpenOnClick输入控制"点击输入框是否打开面板",默认开启(input(true, ...),见 timepicker-input.ts)。若关闭,需要自行实现打开逻辑;
  • 键盘快捷操作:输入框聚焦时按Esc可清空当前值,按/方向键直接打开面板(timepicker-input.ts);
  • 失焦时格式化blur时按当前显示格式把值重新格式化,保证用户交互过程中文本不会被意外改写(timepicker-input.ts)。

Timepicker 的表单集成

Timepicker 输入框完整集成了@angular/forms模块:它自行充当ControlValueAccessorValidator(类声明implements MatTimepickerConnectedInput<D>, ControlValueAccessor, Validator, OnDestroy,见 timepicker-input.ts)。

其行为模型是:当用户在输入框中键入新时间或从下拉列表中选择一项时,该时间会被设置到当前表单控件值所对应的 Date 对象上;如果表单控件当前没有值,timepicker 会用"今天日期 + 所选时间"创建一个新的 Date 对象作为控件值。

官方示例(timepicker-forms-example.html)展示了 Reactive Forms 的用法:

<mat-form-field> <mat-label>Pick a time</mat-label> <input matInput [formControl]="formControl" [matTimepicker]="picker"> <mat-timepicker-toggle matIconSuffix [for]="picker"/> <mat-timepicker #picker/> </mat-form-field> <p>Value: {{formControl.value}}</p> <p>Touched: {{formControl.touched}}</p> <p>Dirty: {{formControl.dirty}}</p>

组件侧(timepicker-forms-example.ts)初始值设为当天 12:30:

export class TimepickerFormsExample { formControl: FormControl<Date | null>; constructor() { const initialValue = new Date(); initialValue.setHours(12, 30, 0); this.formControl = new FormControl(initialValue); } }

toucheddirtyvalue等状态都能被正常追踪,说明 timepicker 输入框与模板驱动表单(ngModel)和响应式表单(formControl)均兼容。

与 MatDatepicker 集成:组合日期时间选择器

Material 的 datepicker 与 timepicker 可以作用在同一个值上,从而组合成一个完整的日期时间选择器。绑定同一个值时:datepicker 负责设置整个 Date 对象,timepicker 只修改其中的时间部分

官方集成示例(timepicker-datepicker-integration-example.html):

<mat-form-field> <mat-label>Meeting date</mat-label> <input matInput [matDatepicker]="datepicker" [(ngModel)]="value"> <mat-datepicker #datepicker/> <mat-datepicker-toggle [for]="datepicker" matSuffix/> </mat-form-field> <mat-form-field> <mat-label>Meeting time</mat-label> <input matInput [matTimepicker]="timepicker" [(ngModel)]="value" [ngModelOptions]="{updateOn: 'blur'}"> <mat-timepicker #timepicker/> <mat-timepicker-toggle [for]="timepicker" matSuffix/> </mat-form-field> <p>Value: {{value()}}</p>

这里两个输入框通过[(ngModel)]="value"共享同一个 Date 对象:日期字段改日期、时间字段改时间,互不覆盖对方的部分。时间输入框使用{updateOn: 'blur'}让模型在失焦时才更新,避免键入过程中因中间态值(如只输入了"12:")触发不必要的变化检测。

输入校验(Input validation)

timepicker 输入框会检查两件事:用户键入的值是否为合法时间字符串,以及是否落在设定的上下界内

解析错误:matTimepickerParse

如果用户键入非法时间字符串(例如abc24:67),输入框会报告matTimepickerParse错误。字符串解析由当前日期实现(DateAdapter)的parseTime方法完成,例如 timepicker-input.ts 中的this._dateAdapter.parseTime(value, this._dateFormats.parse.timeInput)

范围错误:matTimepickerMin / matTimepickerMax

输入框通过matTimepickerMinmatTimepickerMax两个输入限定上下界(timepicker-input.ts)。它们既接受携带具体时间的 Date 对象,也接受时间字符串。这两个输入同时还会控制下拉菜单里显示哪些时间选项:选项只会生成在最小值与最大值之间。

例如,设置matTimepickerMin="12:30"matTimepickerMax="21:25",用户只能选择下午 12:30 到晚上 9:25 之间的时间。一旦值超出范围,输入框会向 value accessor 报告matTimepickerMin(太早)或matTimepickerMax(太晚)错误。

校验器的实现见 timepicker-input.ts:它用Validators.compose组合了三个校验函数,分别产出matTimepickerParsematTimepickerMinmatTimepickerMax错误对象,且错误对象中带有textminmaxactual等便于排错的明细字段。

官方校验示例(timepicker-validation-example.html)演示了如何展示错误:

<mat-form-field> <mat-label>Pick a time</mat-label> <input matInput [formControl]="formControl" [matTimepicker]="picker" matTimepickerMin="12:30" matTimepickerMax="17:30"> <mat-timepicker-toggle matIconSuffix [for]="picker"/> <mat-timepicker #picker/> @if (formControl.errors?.['matTimepickerParse']) { <mat-error>Value isn't a valid time</mat-error> } @if (formControl.errors?.['matTimepickerMin']) { <mat-error>Value is too early</mat-error> } @if (formControl.errors?.['matTimepickerMax']) { <mat-error>Value is too late</mat-error> } </mat-form-field> <p>Enter a value before 12:30 PM or after 5:30 PM to see the errors</p> <p>Errors: {{formControl.errors | json}}</p>

自定义下拉选项

默认情况下,mat-timepicker的下拉列表以30 分钟为间隔生成选项。官方提供两种自定义方式:设置interval(间隔),或传入自定义options数组。

方式一:interval 间隔

mat-timepicker传入interval输入即可改变选项生成间隔,选项会从最小时间开始、到最大时间结束。例如<mat-timepicker interval="90m"/>表示按 90 分钟间隔生成选项。

合法的间隔字符串包括:

写法含义示例
纯数字(按分钟解释)50 表示 50 分钟interval="50"
数字 + 短单位30m表示 30 分钟,5h表示 5 小时;支持h/H(时)、m/M(分)、s/S(秒)interval="30m"interval="5h"
数字 + 长单位75 min表示 75 分钟,1.5 hours表示 1.5 小时;支持min/minute/minutes(分)、hour/hours(时)、second/seconds(秒)interval="75 min"interval="1.5 hours"

间隔字符串的解析逻辑在 util.ts 的parseInterval中:正则INTERVAL_PATTERN/^(\d*\.?\d+)\s*(h|hour|hours|m|min|minute|minutes|s|second|seconds)?$/i)负责拆出数值与单位,再统一换算为秒;小时 ×3600、分钟 ×60、秒 ×1。数字形式则被直接视为秒数。MatTimepicker.interval输入本身也以parseInterval作为 transform(见 timepicker.ts)。

选项的生成则由generateOptions(util.ts)完成:从 min 开始按间隔用adapter.addSeconds累加,直到超过 max 为止,每个选项的标签用formats.display.timeOptionLabel格式化。源码特意对间隔做了Math.max(interval, 1)的下限保护,避免小于 1 秒的间隔"冻结"浏览器。生成结果还有一层缓存:只有当"间隔 + min + max"的组合变化时才重新生成(timepicker.ts)。

全局默认间隔:可以通过MAT_TIMEPICKER_CONFIG注入令牌为整个应用设置默认间隔,例如把所有 timepicker 默认改为 90 分钟间隔:

import {MAT_TIMEPICKER_CONFIG} from '@angular/material/timepicker'; { provide: MAT_TIMEPICKER_CONFIG, useValue: {interval: '90 minutes'}, }

MatTimepickerConfig接口(util.ts)目前支持interval(默认间隔)与disableRipple(默认关闭波纹效果)两个可选字段。

方式二:自定义 options 数组

如果应用需要更细粒度的控制,可以直接向mat-timepicker传入options数组。注意数组元素必须符合MatTimepickerOption接口:

export interface MatTimepickerOption<D = unknown> { /** Date value of the option. */ value: D; /** Label to show to the user. */ label: string; }

官方示例(timepicker-options-example.ts)同时演示了 interval 与自定义 options 两种用法:

export class TimepickerOptionsExample { customOptions: MatTimepickerOption<Date>[] = [ {label: 'Morning', value: new Date(2024, 0, 1, 9, 0, 0)}, {label: 'Noon', value: new Date(2024, 0, 1, 12, 0, 0)}, {label: 'Evening', value: new Date(2024, 0, 1, 22, 0, 0)}, ]; }

对应模板(timepicker-options-example.html):

<mat-form-field> <mat-label>Every 45 minutes</mat-label> <input matInput [matTimepicker]="minutesPicker"> <mat-timepicker-toggle matIconSuffix [for]="minutesPicker"/> <mat-timepicker interval="45min" #minutesPicker/> </mat-form-field> <mat-form-field> <mat-label>Every 3.5 hours</mat-label> <input matInput [matTimepicker]="hoursPicker"> <mat-timepicker-toggle matIconSuffix [for]="hoursPicker"/> <mat-timepicker interval="3.5h" #hoursPicker/> </mat-form-field> <mat-form-field> <mat-label>Pick a time of day</mat-label> <input matInput [matTimepicker]="customPicker"> <mat-timepicker-toggle matIconSuffix [for]="customPicker"/> <mat-timepicker [options]="customOptions" #customPicker/> </mat-form-field>

自定义开关图标

mat-timepicker-toggle默认渲染一个时钟图标。你可以通过向开关内投影一个带有matTimepickerToggleIcon属性的元素来替换它。官方示例(timepicker-custom-icon-example.html):

<mat-form-field> <mat-label>Pick a time</mat-label> <input matInput [matTimepicker]="picker"> <mat-timepicker-toggle matIconSuffix [for]="picker"> <mat-icon matTimepickerToggleIcon>keyboard_arrow_down</mat-icon> </mat-timepicker-toggle> <mat-timepicker #picker/> </mat-form-field>

开关组件(timepicker-toggle.ts)本身还提供for(绑定的 timepicker)、disableddisableRipple(默认读取MAT_TIMEPICKER_CONFIG中的全局配置)等输入,以及ariaLabel/ariaLabelledby等无障碍相关配置。

国际化(Internationalization)

timepicker 的国际化机制与mat-datepicker共用同一个日期适配器,由三个层面共同配置:

  1. 日期 locale(地区代码);
  2. timepicker 接受的日期实现(DateAdapter 实现);
  3. timepicker 使用的显示与解析格式(MAT_DATE_FORMATS)。

设置 locale 代码

默认情况下,MAT_DATE_LOCALE注入令牌会使用@angular/core提供的LOCALE_ID地区代码。如需覆盖,可以显式提供新的值:

bootstrapApplication(MyApp, { providers: [{provide: MAT_DATE_LOCALE, useValue: 'en-GB'}], });

也可以在运行时通过DateAdaptersetLocale方法动态切换地区。官方 locale 示例(timepicker-locale-example.ts)演示了这一点——点击按钮即调用this._adapter.setLocale('bg-BG')切到保加利亚语:

export class TimepickerLocaleExample { private readonly _adapter = inject<DateAdapter<unknown, unknown>>(DateAdapter); value = signal(new Date(2024, 0, 1, 13, 45, 0)); protected switchLocale() { this._adapter.setLocale('bg-BG'); } }

注意:如果使用的是provideDateFnsAdapter,则必须向MAT_DATE_LOCALE提供对应 locale 的 data 对象(而非 locale 代码),同时还要向MAT_DATE_FORMATS提供与date-fns兼容的配置;date-fns的 locale 数据可从date-fns/locale导入。

选择日期实现与格式设置

timepicker 被设计为实现无关(implementation-agnostic),可与mat-datepicker互操作,因此支持多种日期实现——但也意味着开发者需要为所选实现提供配套的适配器。最省事的做法是直接导入官方提供的日期适配器之一。

provideNativeDateAdapterMatNativeDateModule

项目说明
Date 类型Date
支持的 locales使用 AM/PM 或 24 小时制格式化的 locale
依赖
导入来源@angular/material/core

provideDateFnsAdapterMatDateFnsModule(通过ng add @angular/material-date-fns-adapter安装)

项目说明
Date 类型Date
支持的 localesdate-fns项目为准
依赖date-fns
导入来源@angular/material-date-fns-adapter

provideLuxonDateAdapterMatLuxonDateModule(通过ng add @angular/material-luxon-adapter安装)

项目说明
Date 类型DateTime
支持的 locales以 Luxon 项目为准
依赖Luxon
导入来源@angular/material-luxon-adapter

provideMomentDateAdapterMatMomentDateModule(通过ng add @angular/material-moment-adapter安装)

项目说明
Date 类型Moment
支持的 locales以 Moment.js 项目为准
依赖Moment.js
导入来源@angular/material-moment-adapter

重要限制provideNativeDateAdapter的时间解析基于正则实现,只支持 AM/PM 格式(如1:45 PM)或 24 小时格式(如22:4522.45,因此无法适配使用其他格式的 locale。官方建议:要么使用上面列出的官方适配器,要么继承@angular/material/core中的DateAdapter基类自行实现。

例如,改用date-fns适配器时,把bootstrapApplication更新为:

import {provideDateFnsAdapter} from '@angular/material-date-fns-adapter'; bootstrapApplication(MyApp, { providers: [provideDateFnsAdapter()] });

自定义解析与显示格式

MAT_DATE_FORMATS是一组 timepicker 在解析和显示 Date 对象时使用的格式集合,它们会被透传给DateAdapter,因此必须确保所提供格式与当前DateAdapter兼容。

MAT_DATE_FORMATSmat-datepicker使用同一个对象——如果应用已在用 datepicker,这个令牌大概率已经配置好了;但对 timepicker 而言,还必须确保以下三个属性被设置:

  • display.timeInput:输入框 / 选项时间段的显示格式;
  • display.timeOptionLabel:下拉选项中每一条时间的显示格式;
  • parse.timeInput:把用户键入的字符串解析为时间的格式。

这三个属性也是 timepicker 启动时的硬性校验项validateAdapter(util.ts)会检查它们是否缺失,任一缺失都会抛出 "IncompleteMAT_DATE_FORMATS" 错误。

如果希望在官方适配器上使用自己的格式,可以把格式传入 providers 函数,或直接提供MAT_DATE_FORMATS令牌。例如:

bootstrapApplication(MyApp, { providers: [provideNativeDateAdapter(MY_NATIVE_DATE_FORMATS)], });

无障碍(Accessibility)

timepicker 实现了ARIA combobox 交互模式(W3C APG 规范):

  • timepicker 输入框设置role="combobox"
  • 下拉内容设置role="listbox"
  • 下拉中的每个选项设置role="option"

默认情况下 listbox 的标签来自其所在的mat-form-field的 label;如果未使用 form field,或需要自定义标签,可以通过mat-timepickerariaLabelariaLabelledby输入指定。相关输入的定义见 timepicker.ts。此外,键盘交互由ActiveDescendantKeyManager(timepicker.ts)驱动,支持方向键上下移动、Home/End跳转、PageUp/PageDown翻页,保证纯键盘操作可用。

常见错误排查(Troubleshooting)

Error: MatTimepicker: No provider found for DateAdapter/MAT_DATE_FORMATS

这个错误表示 timepicker 所需的注入项(DateAdapterMAT_DATE_FORMATS)未提供完整。最简单的解决方式是在应用配置中加入provideNativeDateAdapterprovideMomentDateAdapter等适配器,详见上文"选择日期实现与格式设置"。

Error: MatTimepicker: IncompleteMAT_DATE_FORMATShas been provided

timepicker 正常工作需要MAT_DATE_FORMATS中包含display.timeInputdisplay.timeOptionLabelparse.timeInput三个字段。请补充这些字段,详见"自定义解析与显示格式"。

Error: Cannot specify both theoptionsandintervalinputs at the same time

一个mat-timepicker不能同时指定optionsinterval两个输入。此校验在组件初始化时执行(见 timepicker.ts),请修改模板移除其中一个。

Error: Value ofoptionsinput cannot be an empty array

传入options输入的数组不能为空——否则用户没有任何选项可选。同样是组件初始化期的硬性校验(timepicker.ts)。

Error: A MatTimepicker can only be associated with a single input

当多个<input>通过matTimepicker属性试图绑定同一个<mat-timepicker>时抛出此错误。一个 timepicker 只能与唯一一个输入框关联(注册逻辑见 timepicker-input.ts 中的_registerTimepicker)。

测试与进一步探索

仓库为 timepicker 提供了完整的三层测试保障,可作为理解行为边界的参考:

  • 组件单元测试:timepicker.spec.ts 覆盖生成选项、校验、键盘交互、min/max 边界等核心行为;
  • 工具函数测试:util.spec.ts 覆盖parseIntervalgenerateOptions等纯函数;
  • Harness 测试:testing/ 目录下的timepicker-harness.spec.tstimepicker-input-harness.spec.tstimepicker-toggle-harness.spec.ts演示了如何用 Component Harness 在测试中打开面板、读取选项、断言值,配套的 harness 实现位于 timepicker-harness.ts 与 timepicker-input-harness.ts。

全部可复现的官方示例集中在 src/components-examples/material/timepicker 目录下,涵盖 overview、forms、validation、options、custom-icon、locale、datepicker-integration、harness 八个主题,适合直接对照学习或拷贝改造。

【免费下载链接】componentsComponent infrastructure and Material Design components for Angular项目地址: https://gitcode.com/GitHub_Trending/co/components

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询