Angular Material Timepicker 组件完全指南:API 结构、表单集成与下拉选项定制
2026/9/12 11:03:54 网站建设 项目流程

Angular Material Timepicker 组件完全指南:API 结构、表单集成与下拉选项定制

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

Angular Material Timepicker 是官方组件库(@angular/material/timepicker)中用于设置日期对象"时间部分"的组件:用户既可以直接在输入框中键入时间,也可以从预定义的下拉选项列表中选取。本文以当前仓库的公开 API 报告(goldens/material/timepicker/index.api.md)为骨架,结合官方指南(src/material/timepicker/timepicker.md)与源码实现(timepicker.ts、timepicker-input.ts、util.ts),系统讲解 Timepicker 的 API 结构、@angular/forms集成、与mat-datepicker组合成日期时间选择器、下拉选项定制、国际化与无障碍配置,帮助你直接落地到实际业务表单中。


一、组件 API 总览:从公开 API 报告认识 Timepicker

goldens/material/timepicker/index.api.md是由 API Extractor 自动生成的公开 API 报告,它精确刻画了@angular/material_timepicker包的对外接口。整包对外导出 3 个组件/指令与 4 个接口、2 个注入令牌:

导出符号类型作用
MatTimepicker<D>组件(selector:mat-timepicker渲染时间下拉面板,管理打开/关闭与选项生成
MatTimepickerInput<D>指令(selector:input[matTimepicker]时间输入框,同时是ControlValueAccessorValidator
MatTimepickerToggle<D>组件(selector:mat-timepicker-toggle用于打开面板的时钟按钮
MatTimepickerModuleNgModule导出以上三者及CdkScrollableModule
MatTimepickerConfig接口全局默认配置(intervaldisableRipple
MatTimepickerConnectedInput<D>接口Timepicker 与输入框之间的连接契约
MatTimepickerOption<D>接口自定义下拉选项结构(label+value
MatTimepickerSelected<D>接口选中事件载荷(value+source
MAT_TIMEPICKER_CONFIG注入令牌覆盖全局默认配置
MAT_TIMEPICKER_SCROLL_STRATEGY注入令牌自定义面板滚动策略

ɵcmp/ɵdir声明可以确认各成员的信号化输入输出关系,例如MatTimepicker的输入有intervaloptionsdisableRipplearia-labelaria-labelledbypanelClass,输出为selectedopenedclosedMatTimepickerInput的输入为valuematTimepicker(必选)、matTimepickerMinmatTimepickerMaxmatTimepickerOpenOnClickdisabled,输出为valueChange。这些映射与源码中input(...)/model(...)/output()的声明一一对应。

1.1MatTimepickerConfigMAT_TIMEPICKER_CONFIG

export interface MatTimepickerConfig { /** Default interval for all time pickers. */ interval?: string | number; /** Whether ripples inside the timepicker should be disabled by default. */ disableRipple?: boolean; }

该令牌定义在 util.ts,MatTimepickerMatTimepickerToggle都会以可选注入的方式读取它(inject(MAT_TIMEPICKER_CONFIG, {optional: true})),用于初始化intervaldisableRipple的默认值。

1.2MatTimepickerConnectedInput:面板与输入框的桥梁

export interface MatTimepickerConnectedInput<D> { value: Signal<D | null>; min: Signal<D | null>; max: Signal<D | null>; disabled: Signal<boolean>; focus(): void; getOverlayOrigin(): ElementRef<HTMLElement>; getLabelId(): string | null; timepickerValueAssigned(value: D | null): void; }

MatTimepickerInput实现该接口并在构造时通过registerInput()注册到 Timepicker(见 timepicker-input.ts)。Timepicker 打开面板时依赖min/max生成选项、依赖getOverlayOrigin()定位浮层、选中后调用timepickerValueAssigned()回写值。


二、最小可运行配置:连接输入框与开关按钮

一个 Timepicker 由"文本输入框 + 下拉面板"组成,二者通过输入框上的matTimepicker绑定关联;mat-timepicker-toggle是可选的开关按钮,便于用户一键展开面板。官方最小示例(见 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>
  • mat-timepicker组件本身没有任何可视化内容,它只是一个"面板逻辑载体",最终通过TemplatePortal挂载到由 CDK Overlay 创建的浮层上(见 timepicker.ts 的open()流程)。
  • mat-timepicker-toggle通过必选输入for(对应timepicker输入信号)指向 Timepicker 实例。
  • 输入框与开关既可以独立使用,也可以像上面这样放进mat-form-field,此时输入框的getOverlayOrigin()会优先返回表单字段的连接原点(见 timepicker-input.ts),面板宽度会跟随输入框宽度(overlayRef.updateSize({width: input.getOverlayOrigin().nativeElement.offsetWidth}))。

使用模块时只需引入MatTimepickerModule(或 Standalone 模式下直接 importMatTimepickerMatTimepickerInputMatTimepickerToggle),该模块同时导出CdkScrollableModule以支持面板内滚动(见 timepicker-module.ts)。


三、表单集成:Timepicker 是原生的表单控件

MatTimepickerInput通过自身提供的NG_VALUE_ACCESSORNG_VALIDATORSMAT_INPUT_VALUE_ACCESSOR三个 provider 接入 Angular 表单体系(见 timepicker-input.ts),这意味着它可以直接用于formControlngModel或响应式表单:

<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>

完整示例见 timepicker-forms-example.html。

关键行为(来自官方指南 "Timepicker forms integration" 一节):

  • 用户键入新时间或从下拉中选择时间后,该时间会被设置到当前表单控件持有的日期对象上,即只修改日期对象的时分秒部分。
  • 如果表单控件当前没有值,Timepicker 会以今天的日期 + 所选时间创建一个新日期对象。
  • ControlValueAccessor接口的writeValue在写入时会先经deserializegetValidDateOrNull清洗,避免无效值污染模型(见 timepicker-input.ts)。
  • 当用户输入非法时间后恢复合法输入时,组件会用_lastValidDate保存的上一个合法日期并覆盖其时间,从而不丢失日期部分(见_assignUserSelection,timepicker-input.ts)。

3.1 与MatDatepicker组合:实现"日期 + 时间"选择器

Material 的 datepicker 与 timepicker 可以作用于同一个值:datepicker 设置整个日期对象,timepicker 只修改其中的时间部分,二者互补即可组合出完整的 datetime 选择器。官方示例(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>

两个组件共享同一个value绑定。由于 timepicker 内部依赖DateAdapter.sameTime判断值是否变化,与 datepicker 共用同一套日期适配器即可保证时间部分的读写一致。示例中为时间输入框设置了updateOn: 'blur',避免键入过程中频繁写值。


四、输入校验:解析错误与上下界约束

官方指南的 "Input validation" 一节明确了 Timepicker 输入框的两类校验职责:时间字符串是否合法是否落在matTimepickerMin/matTimepickerMax边界内

4.1 解析错误matTimepickerParse

当用户键入非法时间字符串(如abc24:67)时,输入框上报matTimepickerParse错误。字符串由当前日期实现的parseTime方法解析——即底层DateAdapter.parseTime(value, MAT_DATE_FORMATS.parse.timeInput)。以原生适配器为例,其TIME_REGEX只接受如下形态(见 native-date-adapter.ts):

  • H:mmH:mm:ss
  • H:mm AM/PMH:mm:ss AM/PM
  • 分隔符:.(即也接受22.45这种写法)

4.2 上下界错误matTimepickerMin/matTimepickerMax

matTimepickerMinmatTimepickerMax输入(别名对应源码中的min/max信号)接受带具体时间的日期对象时间字符串,二者同时决定:

  1. 用户可输入的时间边界;
  2. 下拉面板内实际渲染的选项范围。

示例(官方指南原例):

<input matInput [formControl]="formControl" [matTimepicker]="picker" matTimepickerMin="12:30" matTimepickerMax="17:30">

设置matTimepickerMin="12:30"matTimepickerMax="21:25"后,用户只能在下午 12:30 至晚上 9:25 之间选择;越界值会通过值访问器分别上报matTimepickerMin/matTimepickerMax错误。错误对象的结构(来自 timepicker-input.ts 的验证器组合):

  • matTimepickerParse{text: 用户输入文本}
  • matTimepickerMin{min, actual}actual为反序列化后的当前值)
  • matTimepickerMax{max, actual}

在模板中可用@if配合mat-error展示错误信息(完整示例见 timepicker-validation-example.html):

@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> }

实现上,_updateFormsState()中的 effect 持续计算valueValid_minValid_maxValid三个状态,任一状态变化即触发_validatorOnChange()(见 timepicker-input.ts),验证器使用Validators.compose合并三个校验函数。min/max的字符串输入经_transformDateInput调用parseTime转为日期对象,解析失败则返回null(视为不设界)。


五、自定义下拉选项:interval 与 options

默认情况下,mat-timepicker下拉面板以30 分钟为间隔生成选项。可通过两种方式定制:interval输入或options输入(二者互斥)。

5.1 使用interval输入

<mat-timepicker interval="90m"/>

interval接受字符串或数字,合法的间隔写法(官方指南完整列举):

写法含义说明
5050 分钟纯数字按分钟解释
30m/5h30 分钟 / 5 小时短单位:h/H小时,m/M分钟,s/S
75 min/1.5 hours75 分钟 / 1.5 小时长单位:min/minute/minuteshour/hourssecond/seconds

底层解析由 util.ts 的parseInterval完成,其匹配正则与换算规则如下:

const INTERVAL_PATTERN = /^(\d*\.?\d+)\s*(h|hour|hours|m|min|minute|minutes|s|second|seconds)?$/i;
  • 小时单位 × 3600、分钟单位 × 60、其余按秒处理,最终统一换算为
  • 无法匹配或 NaN 时返回null(回退到默认 30 分钟)。

选项的生成逻辑在_generateOptions()(timepicker.ts):默认间隔为30 * 60秒;起始时间为min(缺省为当天 00:00:00),结束时间为max(缺省为当天 23:59:00);生成结果会以interval/格式化min/格式化max作为缓存键,避免输入未变化时重复计算。generateOptions中还设置了Math.max(interval, 1)的下限,防止亚秒间隔导致浏览器卡死(见 util.ts)。

5.2 通过MAT_TIMEPICKER_CONFIG设置全局默认间隔

若想让应用内所有 Timepicker 默认使用某个间隔,可在providers中提供MAT_TIMEPICKER_CONFIG(官方指南原例):

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

5.3 使用options输入提供完全自定义的选项

当需要更细粒度的控制(比如按业务时间段分组)时,可传入符合MatTimepickerOption接口的数组:

export interface MatTimepickerOption<D = unknown> { value: D; // 选项的日期值 label: string; // 展示给用户的文本 }

官方示例(timepicker-options-example.ts):

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)}, ];
<mat-timepicker [options]="customOptions" #customPicker/>

对应的 HTML 模板中还演示了interval="45min"interval="3.5h"两种间隔写法(见 timepicker-options-example.html)。注意:optionsinterval不能同时指定options不能是空数组——违反这两条规则会在开发模式下直接抛出异常(见 timepicker.ts 的 effect 校验)。


六、自定义开关图标

mat-timepicker-toggle默认渲染一个时钟图标。通过matTimepickerToggleIcon属性将自定义元素投影进按钮内部即可替换(见 timepicker-toggle.html 的ng-content投影逻辑与官方示例 timepicker-custom-icon-example.html):

<mat-timepicker-toggle matIconSuffix [for]="picker"> <mat-icon matTimepickerToggleIcon>keyboard_arrow_down</mat-icon> </mat-timepicker-toggle>

MatTimepickerToggle其余可用输入(来自 API 报告):for(必选)、aria-labelaria-labelledbydisabledtabIndexdisableRipple。默认 ARIA 标签为 "Open timepicker options"(见 timepicker-toggle.ts)。值得注意的实现细节:toggle 的点击事件绑定在宿主元素上并在打开面板后调用event.stopPropagation(),以避免表单字段自动聚焦到输入框(见 timepicker-toggle.ts)。


七、国际化:语言、日期实现与显示格式

Timepicker 的国际化与mat-datepicker共享同一套DateAdapter机制,由三个要素共同决定:

  1. 日期 localeMAT_DATE_LOCALE);
  2. 日期实现(Native / date-fns / Luxon / Moment 适配器);
  3. 显示与解析格式MAT_DATE_FORMATS)。

7.1 设置 locale

默认情况下MAT_DATE_LOCALE使用@angular/coreLOCALE_ID。要覆盖它,可在启动配置中提供新值:

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

也可以在运行时通过DateAdapter.setLocale()动态切换。官方示例即用一个按钮在运行期把 locale 切到保加利亚语(timepicker-locale-example.ts):

this._adapter.setLocale('bg-BG');

注意:若使用provideDateFnsAdapterMAT_DATE_LOCALE需要提供该 locale 的数据对象(从date-fns/locale导入)而非 locale 代码,同时还需向MAT_DATE_FORMATS提供与date-fns兼容的配置。

7.2 选择日期实现

Timepicker 与实现无关(implementation-agnostic),官方推荐直接使用随包提供的适配器之一:

适配器(函数式 / 模块式)日期类型依赖引入位置
provideNativeDateAdapter/MatNativeDateModuleDate@angular/material/core
provideDateFnsAdapter/MatDateFnsModuleDatedate-fns@angular/material-date-fns-adapterng add @angular/material-date-fns-adapter
provideLuxonDateAdapter/MatLuxonDateModuleDateTimeLuxon@angular/material-luxon-adapter
provideMomentDateAdapter/MatMomentDateModuleMomentMoment.js@angular/material-moment-adapter

例如使用 date-fns 适配器:

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

原生适配器的时间解析限制provideNativeDateAdapter通过正则实现时间解析,只支持 AM/PM 时间(如1:45 PM)或 24 小时制时间(如22:4522.45),无法适配格式不同的 locale。若 locale 格式特殊,建议换用上述其他适配器,或通过继承DateAdapter类(@angular/material/core)自行实现。

7.3 自定义解析与显示格式:MAT_DATE_FORMATS

Timepicker 使用MAT_DATE_FORMATS对象解析与显示日期对象,其格式最终透传给DateAdapter,因此提供的格式必须与所选适配器兼容。MAT_DATE_FORMATSmat-datepicker共用同一个令牌——如果应用已在用 datepicker,通常已配置好,但timepicker 额外要求以下三个字段必须存在:

  • display.timeInput
  • display.timeOptionLabel
  • parse.timeInput

以内置的MAT_NATIVE_DATE_FORMATS为例(native-date-formats.ts):

export const MAT_NATIVE_DATE_FORMATS: MatDateFormats = { parse: { dateInput: null, timeInput: null, // 解析时间输入 }, display: { dateInput: {year: 'numeric', month: 'numeric', day: 'numeric'}, timeInput: {hour: 'numeric', minute: 'numeric'}, // 输入框显示格式 monthYearLabel: {year: 'numeric', month: 'short'}, dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'}, monthYearA11yLabel: {year: 'numeric', month: 'long'}, timeOptionLabel: {hour: 'numeric', minute: 'numeric'}, // 下拉选项显示格式 }, };

validateAdapter(util.ts)会在组件构造时校验适配器与格式:缺少DateAdapter/MAT_DATE_FORMATS提供者、或上述三个 time 格式字段缺失时,会抛出下文"疑难解答"中对应的错误。

如果想使用官方适配器但换成自己的格式,有两种方式:把格式对象传给 providers 函数,或自行提供MAT_DATE_FORMATS令牌:

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

八、无障碍(Accessibility)

Timepicker 实现了 ARIA combobox 交互模式,其 ARIA 角色分配如下:

  • 输入框:role="combobox"aria-haspopup="listbox",并根据面板状态动态维护aria-expandedaria-controlsaria-activedescendant(见 timepicker-input.ts 的宿主绑定与_ariaActiveDescendant/_ariaExpanded/_ariaControls三个 computed 信号);
  • 面板容器:role="listbox"(见 timepicker.html);
  • 面板内每个选项:role="option"(由mat-option提供)。

默认情况下,listbox 通过所在mat-form-field的标签来标注(_getAriaLabelledby()会回退到ariaLabelledby或输入框的getLabelId(),见 timepicker.ts)。如果不使用表单字段或想自定义标签,可通过mat-timepickerariaLabel/ariaLabelledby输入设置。

键盘交互方面,面板打开后由ActiveDescendantKeyManager驱动方向键导航(支持 Home/End、PageUp/PageDown、纵向方向键,见 timepicker.ts),Enter选中当前项、Escape关闭、Tab关闭面板,且在关闭时调用scrollOptionIntoView保证活动项可见(_handleKeydown,timepicker.ts)。


九、疑难解答(Troubleshooting)

官方指南总结了 5 类常见错误及解决方案,以下全部可在源码中找到对应的抛错点:

  1. MatTimepicker: No provider found for DateAdapter/MAT_DATE_FORMATS未提供 Timepicker 工作所需的注入项。解决:在应用配置中加入provideNativeDateAdapter()provideMomentDateAdapter()等适配器(见 util.ts 的missingAdapterError)。

  2. MatTimepicker: Incomplete MAT_DATE_FORMATS has been provided提供的MAT_DATE_FORMATS缺少display.timeInputdisplay.timeOptionLabelparse.timeInput字段。解决:按上文 7.3 节补齐这三个字段(见 util.ts)。

  3. Cannot specify both the options and interval inputs at the same timeoptionsinterval互斥,模板中需移除其中一个(见 timepicker.ts)。

  4. Value of options input cannot be an empty arrayoptions不能为空数组,否则用户无任何可选项(见 timepicker.ts)。

  5. A MatTimepicker can only be associated with a single input同一个<mat-timepicker>只允许一个<input>通过matTimepicker属性关联;当第二个输入框试图注册时抛出(见 timepicker.ts 的registerInput)。


十、深入源码:面板的生命周期与值回写

最后从源码层面对照 API 报告,理解几个关键机制的实现(均为可验证的实现事实):

  • 打开流程open()先聚焦输入框,随后_generateOptions()按当前interval/optionsmin/max生成选项,再通过 CDK Overlay 创建浮层(createFlexibleConnectedPositionStrategy,首选"输入框下方对齐"、次选"上方对齐"并附加mat-timepicker-above类),使用TemplatePortal挂载面板模板,并注册detachmentskeydownEventsoutsidePointerEvents三个订阅(timepicker.ts)。
  • 选中回写_selectValue(option)先关闭面板、同步选中态,然后调用_input().timepickerValueAssigned(option.value)让输入框更新表单控件,发射selected事件(timepicker.ts);输入框侧timepickerValueAssigned比较sameTime后经_assignUserSelection_onChange传播给表单并更新valuemodel(timepicker-input.ts)。
  • 键盘直达:输入框聚焦时按上/下方向键会直接open()_handleKeydown,timepicker-input.ts),Escape可清空当前值。
  • locale 联动DateAdapter.localeChanges被订阅后,若面板处于打开状态会重新生成选项、输入框在失焦状态下会重新格式化显示值,保证语言切换即时生效(timepicker.ts)。
  • 滚动策略MAT_TIMEPICKER_SCROLL_STRATEGY默认提供createRepositionScrollStrategy(timepicker.ts),面板打开期间页面滚动时会跟随输入框重定位。

结语

本文以公开 API 报告 goldens/material/timepicker/index.api.md 为主线,完整覆盖了MatTimepickerMatTimepickerInputMatTimepickerToggle三个构件及MAT_TIMEPICKER_CONFIGMAT_TIMEPICKER_SCROLL_STRATEGY两个令牌的用法,并延伸到表单集成、日期选择器组合、校验、选项定制、国际化与无障碍。实战中只需记住三件事:matTimepicker绑定输入框、按需提供日期适配器(provideNativeDateAdapter起步)、用interval/options控制面板选项,即可在表单中快速交付专业的时间选择体验。

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

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

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

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

立即咨询