Handsontable 时间单元格类型(Time Cell Type)完整指南:基于 Intl.DateTimeFormat 的时间格式化、校验与编辑
【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址: https://gitcode.com/gh_mirrors/ha/handsontable
本指南围绕 Handsontable 官方文档 time-cell-type.md 展开,结合仓库内
handsontable/src/cellTypes/下intlTimeType、timeType的源码实现与示例代码,系统讲解如何用intl-time/time单元格类型展示、格式化、校验、编辑、排序与过滤时间值。
Handsontable 的intl-time与time单元格类型(cell type)用于把单元格值当作时间来处理:通过可配置的格式字符串控制显示样式,并校验用户输入。它基于浏览器原生的Intl.DateTimeFormatAPI,适用于排班(scheduling)、日志(logging)或任何基于时间的数据场景。阅读本文后,你将掌握:在整表、单列或单单元格上配置时间单元格类型;使用timeFormat对象定制显示格式与 locale;理解源码层的数据格式约束与校验逻辑;以及时间值在排序、过滤与编辑中的行为。
概览(Overview)
时间单元格类型让你将单元格值视作时间:格式化其显示方式,并校验输入。使用intl-time或time单元格类型,配合原生Intl.DateTimeFormatAPI 与 24 小时制时间字符串。
从源码结构看,这两种类型在handsontable/src/cellTypes/目录中各自独立实现:
handsontable/src/cellTypes/intlTimeType/intlTimeType.ts定义CELL_TYPE = 'intl-time',组合了IntlTimeEditor、intlTimeRenderer、intlTimeValidator、sourceDataValidator与valueFormatter;handsontable/src/cellTypes/timeType/timeType.ts定义CELL_TYPE: 'time' = 'time',组合了TimeEditor、timeRenderer、timeValidator等。
两者均挂载在handsontable/src/cellTypes/registry.ts的单元格类型注册表中,可通过type: 'intl-time'或type: 'time'直接使用。
时间单元格类型演示
在官方演示(见docs/content/guides/cell-types/time-cell-type/javascript/example1.js)中,Start、Break start与End三列使用时间单元格类型并配以不同格式:短样式(timeStyle: 'short')、自定义"时:分:秒"格式(hour/minute/second),以及带日周期(dayPeriod)的格式。演示还提供了 locale 选择器,切换后会调用hot.updateSettings({ locale: ... })实时重渲染,观察同一timeFormat在不同 locale 下的显示差异。
示例数据采用 24 小时制字符串,例如:
const data = [ { shift: 'Morning', start: '09:00', breakStart: '12:00', end: '17:00' }, { shift: 'Afternoon', start: '13:30', breakStart: '16:00', end: '21:00' }, { shift: 'Night', start: '22:00', breakStart: '01:00', end: '06:00' }, { shift: 'Split', start: '08:00', breakStart: '12:30', end: '20:00' }, { shift: 'Short day', start: '10:00', breakStart: '13:00', end: '15:00' }, ];对应的列配置为:
columns: [ { type: 'text', data: 'shift' }, { type: 'intl-time', data: 'start', timeFormat: { timeStyle: 'short' } }, { type: 'intl-time', data: 'breakStart', timeFormat: { hour: '2-digit', minute: '2-digit', second: '2-digit' } }, { type: 'intl-time', data: 'end', timeFormat: { hour: 'numeric', hourCycle: 'h12', dayPeriod: 'short' } }, ], columnSorting: true, filters: true, dropdownMenu: true,该演示同时启用了columnSorting、filters与dropdownMenu,直接验证了时间列上的排序与过滤能力。演示完整 HTML 骨架见 example1.html,React、Angular、Vue 版本分别位于 example1.jsx、example1.tsx、example1.ts、example1.html 与 example1.vue。
使用时间单元格类型
使用对象式(object-style)配置:将type选项设为'intl-time'或'time',并把timeFormat设为对象。locale 通过locale选项单独控制。
为整个表格设置
// set the time cell type for the entire grid type: 'intl-time', locale: 'en-US', timeFormat: { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true },为单个列设置
columns: [ { type: 'intl-time', locale: 'en-US', timeFormat: { timeStyle: 'medium' } } ],为单个单元格设置
cell: [ { row: 0, col: 2, type: 'intl-time', locale: 'en-US', timeFormat: { hour: '2-digit', minute: '2-digit', hour12: true } } ],说明:
timeFormat的默认值见handsontable/src/renderers/timeRenderer/timeRenderer.ts中的DEFAULT_INTL_FORMAT({ hour: 'numeric', minute: '2-digit' })。即不显式配置时,默认显示"时:分"。
对于intl-time与time单元格,源数据必须是 24 小时制时间格式(HH:mm、HH:mm:ss或HH:mm:ss.SSS),时间才能正常工作。timeFormat对象只影响显示;排序与过滤依赖底层值。
格式化时间
要控制时间在单元格渲染器中的显示方式,使用timeFormat选项。
自 Handsontable 18.0 起,timeFormat的对象形式与intl-time、time单元格类型为必选项。它使用原生Intl.DateTimeFormatAPI;locale 通过locale选项单独控制。
使用 Intl.DateTimeFormat
timeFormat接受Intl.DateTimeFormatoptions 中与时间相关的属性,搭配type: 'intl-time'或type: 'time'使用:
columns: [ { type: 'intl-time', locale: 'en-US', timeFormat: { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true } }, { type: 'intl-time', locale: 'de-DE', timeFormat: { timeStyle: 'medium' } } ]注意:从源码看,若把
timeFormat传成字符串,valueFormatter会在控制台输出警告"The timeFormat option as a string is not supported. Use an Intl.DateTimeFormatOptions object instead.",并回退到默认格式——因此请始终使用对象形式。
时间专属选项
样式快捷方式:
| 属性 | 可选值 | 说明 |
|---|---|---|
timeStyle | 'full'、'long'、'medium'、'short' | 时间格式样式(时、分、秒、timeZoneName) |
时间分量选项:
| 属性 | 可选值 | 说明 |
|---|---|---|
hour | 'numeric'、'2-digit' | 小时表示 |
minute | 'numeric'、'2-digit' | 分钟表示 |
second | 'numeric'、'2-digit' | 秒表示 |
fractionalSecondDigits | 1、2、3 | 秒的小数位 |
dayPeriod | 'narrow'、'short'、'long' | 日周期(如 "am") |
timeZoneName | 'long'、'short'、'shortOffset'、'longOffset'、'shortGeneric'、'longGeneric' | 时区显示 |
Locale 与其他选项:
| 属性 | 可选值 | 说明 |
|---|---|---|
localeMatcher | 'best fit'(默认)、'lookup' | Locale 匹配算法 |
timeZone | IANA 时区(如'UTC'、'America/New_York') | 格式化使用的时区 |
hour12 | true、false | 12 小时制 vs 24 小时制 |
hourCycle | 'h11'、'h12'、'h23'、'h24' | 小时周期 |
formatMatcher | 'basic'、'best fit'(默认) | 格式匹配算法 |
完整参考见timeFormatAPI 文档 或 MDN: Intl.DateTimeFormat。
编辑器行为
timeFormat控制时间在单元格中的显示。编辑器可能会以规范化形式显示值;对于intl-time与time,底层值始终保持 24 小时制(HH:mm、HH:mm:ss或HH:mm:ss.SSS)。
从源码看,TimeEditor继承自TextEditor,但把输入元素创建为原生type="time"的 input,并强制dir="ltr";打开编辑器时会调用原生showPicker()弹出系统时间选择器;若传入的值不满足 24 小时制格式,会输出警告并清空输入。IntlTimeEditor(见handsontable/src/editors/intlTimeEditor/intlTimeEditor.ts)则直接继承TimeEditor,仅替换类型标识。
结果(Result)
配置完成后,单元格按你的timeFormat配置显示格式化后的时间值。点击intl-time或time单元格会打开原生时间选择器。无论显示格式如何,源数据始终以 24 小时制(HH:mm、HH:mm:ss或HH:mm:ss.SSS)存储。
键盘快捷键
intl-time与time单元格编辑器打开浏览器原生时间选择器。选择器内部的键盘导航来自浏览器,因此在不同浏览器与操作系统间有所差异。选择器之外,标准编辑键盘快捷键适用。
深入原理:底层的数据格式与校验
理解源码能帮你避免"显示正常但数据异常"的坑:
时间正则与解析
handsontable/src/helpers/dateTime.ts中定义了 24 小时制时间正则:
export const TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d)(?:\.(\d{1,3}))?)?$/;isValidTime(value):判断字符串是否匹配上述HH:mm、HH:mm:ss或HH:mm:ss.SSS模式;parseToLocalTime(value):把 24 小时制时间字符串解析为本地时区的Date(基准日期为1970-01-01),再交给Intl.DateTimeFormat做显示格式化。这也解释了为什么timeFormat中的timeZone选项会影响显示:格式化发生在解析出的本地Date之上。
校验器与源数据校验
handsontable/src/validators/timeValidator/timeValidator.ts中:
timeValidator:单元格编辑时的校验器,allowEmpty时允许空值,否则用isValidTime校验;sourceDataValidator:批量加载/写入源数据时逐格校验,同样基于isValidTime;当单元格元数据allowEmpty为空值时放行;以=开头的字符串视为公式表达式(由 Formulas 插件处理)而跳过校验;并标记rowIndependent = true以允许源数据校验复用列级 meta 对象,提升性能;SOURCE_DATA_WARNING_MESSAGE:源数据中出现不合法时间值时输出的警告文案,明确指出期望HH:mm、HH:mm:ss或HH:mm:ss.SSS格式。
intlTimeValidator直接委托timeValidator,仅替换类型标识。因此两种单元格类型在编辑校验与源数据校验上行为一致。
排序与过滤依赖底层值
由于排序与过滤基于单元格底层值(24 小时制字符串)而非渲染后的显示文本,相同时间在不同 locale/格式下仍能正确排序、过滤——这正是指南开头强调"源数据必须 24 小时制"的原因。演示中columnSorting: true与filters: true即为该能力的直接验证。
相关文章
相关指南
- 单元格类型(Cell type)
配置选项
- timeFormat
- locale
- type
- valueFormatter
- valueParser
- valueSetter
- valueGetter
核心方法
- getCellMeta()
- getCellMetaAtRow()
- getCellsMeta()
- getDataType()
- setCellMeta()
- setCellMetaObject()
- removeCellMeta()
钩子(Hooks)
- afterGetCellMeta
- afterSetCellMeta
- beforeGetCellMeta
- beforeSetCellMeta
【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look & Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址: https://gitcode.com/gh_mirrors/ha/handsontable
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考