datepicker 输入允许用户从可定制的日历中选择日期,并直接在输入中键入日期,完全支持国际化。
FormKit 使用独特的遮罩解决方案,允许用户在日期选择器输入中键入日期(同时将可用选项限制为仅有效值)或通过日历输入选择日期。
要在双重输入模式下显示占位符,您必须启用遮罩 覆盖。在启用 仅选择器 的情况下,这不是必需的。了解更多关于遮罩和覆盖层的信息。
您可以禁用文本输入机制,并确保某人使用日期选择器对话框输入他们的日期,通过添加 picker-only 属性。在 picker-only 模式下,点击输入将立即打开对话框。此外,不需要使用 覆盖 来支持占位符:
日期选择器支持 Intl.DateTimeFormat "样式化日期",以及基于令牌的日期格式。要更改显示给用户的格式,请修改 format 属性。
如果您的受众是国际性的,您应该考虑坚持使用"样式日期",因为它们是每个地区最自然的日期格式。日期选择器的默认格式是 long。
format 属性可以接受一个简单的字符串,如 long 或 medium,在这种情况下,它使用相应的 Intl.DateTimeFormat dateStyle。或者,您可以提供一个带有 date 和 time 属性及其各自的 Intl.DateTimeFormat 样式的对象({ date: 'long', time: 'short' })。
使用 format 属性启用以下任何日期样式:
| 格式样式 | 示例 |
|---|---|
| full | Wednesday, March 1, 2023, 2023年3月1日星期三 |
| long | March 1, 2023, 2023年3月1日 |
| medium | Mar 6, 2023, 2023年3月6日 |
| short | 3/1/23, 23/3/1 |
| 格式样式 | 示例 |
|---|---|
| long | 7:05:00 PM, 19:05:00 |
| medium | 7:05:00 PM, 19:05:00 |
| short | 7:05 PM, 19:05 |
您可以使用 format 属性来显式设置一个令牌化的日期格式。令牌格式由任意字符和下表中的一个或多个字符串表示。
FormKit 通过 Intl.DateTimeFormat 自动根据当前的 locale 国际化令牌。例如,对于 2000-01-01,令牌 MMMM 在 en 区域设置中会产生 January,但在 zh 区域设置中会产生 一月。
使用令牌时,可能会创建无法解析的日期。例如,如果您的输入只显示星期几(dddd)。您只能在 picker-only 模式下使用无法解析的日期格式。如果您希望允许用户输入他们的日期,您的格式必须至少包括一个月、日和年的令牌。
| 令牌 | 示例 | 描述 |
|---|---|---|
YY | 99, 23, 00 | 2位数年份 |
YYYY | 1999, 2023, 2100 | 4位数年份 |
M | 1, 12 | 月份 1-12 |
MM | 01, 12 | 月份 01-12 |
MMM | Jan, Feb | 简短的月份名称 Jan-Dec |
MMMM | January, February | 完整的月份名称 January - December |
D | 1, 9, 22 | 月份中的一天 1-31 |
DD | 01, 09, 22 | 月份中的一天 01-31 |
d | M, T, W, T, F, S, S | 单个数字的天 "T" |
ddd | Thu, Sat | 简短的星期名称 "Thu" |
dddd | Monday, Tuesday | 完整的星期名称 "Wednesday" |
H | 0, 13, 23 | 最小小时数字,24小时制,0-23 |
HH | 00, 13, 23 | 2位小时数字,24小时制,00-23 |
h | 12, 1, 11 | 最小小时数字,12小时制,1-12 |
hh | 12, 01, 11 | 2位小时数字,12小时制,01-12 |
m | 1, 59 | 分钟 0-59 |
mm | 01, 59 | 分钟 00-59 |
s | 1, 59 | 秒 0-59 |
ss | 01, 59 | 秒 00-59 |
a | am, pm | am/pm |
A | AM, PM | AM/PM |
虽然 FormKit 会自动国际化您的令牌 —— 如果您的表单是为广泛的国际受众设计的,那么考虑使用日期样式而不是令牌,因为这会在许多地区产生更易读的日期。
如果你的格式中包含了本身就是标记的字母(如 a),你可以在字符前使用反斜杠 \ 来转义这些标记:
日期选择器的日历弹出窗口有四个"面板":
day — 显示一个月的传统日历视图,每一天都可以选择。month — 显示一年的12个月份。year — 一次显示十年的年份。time — 显示一天的时间。当用户打开日期选择器的弹出窗口时,他们将看到这些面板中的一个或多个。你可以通过提供一个 sequence 属性来修改哪些面板应该显示给用户,以及这些面板应该按什么顺序显示。默认的 sequence 值是 ['day'](这允许你导航到 month 和 year 面板)。
例如,当选择生日时,首先自然是选择出生年份,然后是月份,最后是日期。sequence 属性允许这种行为:
time 面板可以用来让用户选择一天中的特定时间。如果你选择了包含时间的 format(如 YYYY-MM-DD HH:mm),你可能会希望在你的序列中包含 time 面板:
像所有输入一样,日期选择器的 value 既是由日期选择器产生的,也是读回到日期选择器中进行填充的。默认情况下,值的格式是一个UTC标准化的 ISO8601 字符串(例如:2014-11-27T03:59:00.000Z)。然而,这种格式可以通过使用 value-format 属性改变为任何支持的日期样式或标记格式 上面列出的。
一个合理的问题是,为什么不总是使用 ISO8601?虽然它是处理日期的最流行的方式 - 它既可以被机器读取,也可以被人类读取 - 但它并不是非常适合人类阅读。例如,如果你的表单发送一个联系请求邮件给一个餐饮业务,那么 ISO8601 可能不是最好的选择。
值的格式必须包含所有必要的数据来重新构造一个日期对象,至少包括月份、日期、年份。如果你的输入从用户那里请求的信息在你的值格式中没有表示,那么这些细节将会丢失。
要将日期样式用作值,只需将您想要使用的样式传递给 value-format 属性:
值也可以通过使用格式化令牌以任意格式表示:
传递给日期选择器的值必须:
value-locale 中的 value-format,或者,Date 对象。尽管原生 Date 对象总是被接受为日期选择器的有效输入,但它们将立即转换为指定的 value-format。
value-formatDate由于需要使用创建它的同一区域设置来解析值的格式,因此建议在定义自定义 value-format 时始终指定 value-locale。这确保无论输入日期的用户的区域设置是什么,值都会保持一致:
更改 value-locale 对所选日期的 timezone 没有影响。有关更多解释,请参见下面的时区文档。
在任何软件环境中,时间都是一个难以处理的问题,尤其是在基于浏览器的 JavaScript 中。datepicker 提供了一些选项来帮助解决这些挑战。
为了在 JavaScript 中处理日期和时间,对 Date 对象有基本的理解是有用的。JavaScript 中的日期对象基本上是一个 Unix 时间戳(自 1970年1月1日00:00:00Z 以来的毫秒数)。然而,它始终根据客户端的时间进行本地化。这种本地化以 UTC 的偏移量表示。您的浏览器的当前时间是:
当偏移量应用到 "时钟时间" 时,您将得到当前的 UTC 时间:
当在日期选择器中使用 value-format 令牌时,这些令牌将使用客户端的时区。例如,如果您的格式请求 HH 令牌,它将返回:
将其与上述日期进行比较,您会发现它与本地时间的 hours 部分相同。为什么这很重要?请继续阅读。
让我们考虑一个位于阿姆斯特丹(UTC +100/+200)的餐厅的预订应用。这是游客的热门目的地,他们经常在出行前几周就进行预订(在他们的家乡)。
默认情况下,日期选择器会询问游客他们希望预订的日期和时间 - 但(默认情况下)选择的将是他们的本地时间,而不是阿姆斯特丹的时间。尽管value-format输出的是UTC,但时间并不是他们在阿姆斯特丹预定的预期时间(除非他们恰好在同一时区)。
一般来说,解决这个问题有两种方案:
使用一个"不确定"的时间(有时被称为"墙时间")。不确定的时间是没有特定关联到底层Unix时间戳的时间。例如,3月13日下午2点不是UTC,也没有明确的偏移。3月13日下午2点描述的是在不确定的位置/时区的特定时间。只要你不在你的值(Z)中使用偏移,你就可以使用格式令牌(YYYY-MM-DD HH:mm)来做到这一点。
只要后端能够将适当的时区或偏移附加到这个不确定的时间2023-03-13 14:00 GMT+0100,以得到适当的UTC时间(这是这个虚构的应用在其数据库中需要的),这就可以用于我们的餐厅应用。对于后端开发者来说,剩下的挑战是知道应该将什么偏移应用到日期上,以确保它变成"阿姆斯特丹时间"(由于Europe/Amsterdam的夏令时,这个偏移根据一年中的时间而变化)。
timezone属性另外,日期选择器的timezone属性会自动为你进行偏移校正。只需声明日期选择器是为"哪里"选择时间 - 在我们的例子中是timezone="Europe/Amsterdam"。用户的体验不会有任何改变,但他们选择的时间将是目标时区的时间。一个在America/New_York(+0400)的用户,如果在他们的日期选择器中选择3月13日下午2点,将得到一个UTC值2023-03-13T13:00:00Z,这是阿姆斯特丹的下午2点。这允许你使用UTC格式简单地存储和恢复你的日期。
默认情况下,日期选择器在选择时使用客户端的本地时区。输出的值由value-format决定(见上文) - 默认情况下,这是一个UTC标准化的ISO8601字符串。然而,通过指定一个自定义格式,你可以实现一个"不确定"的时间(也叫"墙时间")。这是一个没有特定关联到给定时区的日期和/或时间。
例如,当你在手机上设置一个早上8:00的闹钟时 - 那个时间是"不确定"的 - 它与时区无关。如果你住在罗马,然后去东京,你的闹钟会在东京的早上8:00响,就像在罗马的早上8:00一样。这是无法用UTC表示的。
你可以通过在你的value-format中不提供任何时区或偏移信息,来使用日期选择器实现不确定的时间 - 添加这些信息取决于日期的解释者。value-format中的令牌总是输出本地客户端的值 - 所以,通过在值中省略任何时区或偏移(Z)数据,它本质上就是"不确定"的:
对于一些应用程序,需要选择给定位置的时间 - 这可能相当具有挑战性。为了帮助缓解这种痛苦,日期选择器支持明确指定输入的 timezone。
timezone 属性允许您根据浏览器支持的 IANA 时区 指定日期选择器的 "位置"。当您希望允许用户在给定地理位置选择日期和时间时,这很重要,无论客户端的位置在哪里。一些示例用例包括:
有很多时候 timezone 不应该被使用(默认为客户端时间):
在下面的例子中,用户需要在国际航班后在印度加尔各答取一辆租赁车。用户查看他们的票 - 飞机在加尔各答的到达时间为 1:45 PM。他们希望在 2:30 PM 之后的 45 分钟内取车。无论用户从世界上的哪个地方预订旅行,这些事实都是真实的。在这种情况下,我们应该将时区设置为 Asia/Kolkata。加尔各答的偏移量为 +5:30 - 因此在 Kolkata 选择 2:30 PM 相当于 09:00 AM UTC:
大多数浏览器都内置了全面的 IANA 数据库 Intl.DateTimeFormat。这非常好,因为 FormKit 不需要将(相当广泛的)时区数据库发送到客户端的浏览器。然而,一些较旧的浏览器可能没有 IANA 数据库。这些数据可以通过使用 polyfill.io 与 Intl.DateTimeFormat.~timeZone.all 轻松填充。
经常需要在日期选择器中禁用特定日期。在日期选择器中禁用日期有三种方式:
min-date - 一个属性,用于控制第一个可用日期是什么。max-date - 一个属性,用于控制最后一个可用日期是什么。disabled-dates - 一个属性,用于控制是否应禁用任意日期。任何被禁用的日期都不能在日期选择器的弹出窗口中选择,但是不可用的日期仍然可以设置为初始值或通过输入到输入框中(当它不在 picker-only 模式下)。为了处理这些边缘情况,日期选择器有一个内置的验证规则(不能被禁用),确保只有有效的日期可以被提交。验证规则的键是 invalidDate。
我们经常需要禁用早于特定日期的日期。例如,预订酒店房间只应在未来的日期进行。为此,使用 min-date 属性,可以是与 ISO8601 兼容的字符串或原生的 Date 对象:
要禁用给定日期后的所有日期,使用 max-date 属性。例如,生日选择器只应允许过去的日期。为此,使用 max-date 属性,可以是与 ISO8601 兼容的字符串或原生的 Date 对象:
您可以同时使用 min-date 和 max-date。这不仅会限制日期的范围,而且在使用文本输入时,它还会将可用的年份限制为仅有效的年份。
我们的应用程序经常需要在禁用日期时具有比 min-date 和 max-date 允许的更多的精细度。日期选择器通过利用 disabled-days 属性允许进行细粒度控制。
disabled-days 属性期望一个函数,该函数传递2个参数:核心节点 和一个 Date 对象。该函数的责任是返回一个布尔值,表示日期是否被禁用(true 表示禁用)。
disabled-days 属性取代了 min-date 和 max-date —— 您可以选择通过访问 node.props.minDate 或 node.props.maxDate 来重新实现基础功能。
提供的函数必须快速且同步 —— 它将被频繁且反复地调用。例如,如果您需要从数据库获取信息,请在此函数之外执行,并使用此函数来访问备忘录结果。
当通过键盘导航日历弹出窗口时,日期选择器不会允许您选择一个禁用的日期。然而,如果一些可用的日期被不可用的日期"夹住",这可能会很烦人,因为它可能会创建无法访问的区域。
为了提高用户体验,日期选择器将自动向前或向后(取决于所需的方向)扫描以选择下一个可用的日期。扫描可用日期的最大天数由 maxScan 属性控制(默认为7天):
| Prop | Type | 默认 | 描述 |
|---|---|---|---|
| date-format | string | D | 在日历中用于月份日期的令牌格式。 |
| disabled-days | function | min/max date logic | 一个函数,传递核心节点和一个 `Date` 对象,并必须返回日期是否被禁用(`true` 是禁用)。 |
| format | string/object | date: 'long' | 在选择输入中显示给用户的格式。 |
| max-date | Date | ISO8601 | none | 用户允许选择的最大日期。 |
| max-scan | number | 7 | 在寻找可用日期以通过键盘导航跳转时,向前或向后扫描的最大天数。 |
| min-date | Date | ISO8601 | none | 用户允许选择的最早日期。 |
| month-button-format | string | MMMM | 在日历弹出窗口中用于月份面板按钮的日期格式令牌。 |
| month-format | string | MMMM | 在月份面板上用于每个月的日期格式令牌。 |
| overlay | boolean | false | 是否显示遮罩覆盖层。在遮罩输入文档中阅读更多关于覆盖层的信息(在 pickerOnly` 模式下无效)。 |
| picker-only | boolean | false | 是否允许通过文本输入输入日期。当启用 picker-only 时,只能使用选择器选择日期。 |
| show-months | number | 1 | 在日面板上弹出时要渲染的月份数量。 |
| sequence | array | ['day'] | 当用户打开日期选择器日历视图时,引导用户的面板序列。选项是 `year`、`month`、`day`、`time`。 |
| value-format | string/object | ISO8601 | 作为输入值的格式。这可以与任何令牌格式、日期样式或 `ISO8601` 组合。 |
| value-locale | string | `node.props.locale` | 用于 `valueFormat` 的语言环境。在 `valueFormat` 属性中使用格式令牌时,强烈建议设置一个明确的 `valueFormat`。 |
| week-start | number | 0 | 开始 `day` 面板的日历的一周的第一天。0-6,其中 0 = 星期日,6 = 星期六。 |
| week-day-format | string | d | 用于渲染星期列标题的日期格式令牌。 |
| year-format | string | YYYY | 用于在 `year` 面板中渲染年份的日期格式令牌。 |
| 显示 通用 props | |||
| config | Object | {} | 提供给 input 的节点和此输入的任何后代节点的配置选项。 |
| delay | Number | 20 | 在调度 commit hook 前,输入值的去抖动毫秒数。 |
| dirtyBehavior | string | touched | 确定此输入的“dirty”标志设置方式。可以设置为 touched 或 compare — 默认为 touched,性能更好,但无法检测表单是否再次匹配其初始状态。 |
| errors | Array | [] | 要在此字段上显示的错误消息的字符串数组。 |
| help | String | '' | 帮助文本与输入关联的文本。 |
| id | String | input_{n} | 输入的唯一标识符。提供一个 id 还可以全局访问输入的节点。 |
| ignore | Boolean | false | 防止将输入包含在任何父级(组、列表、表单等)中。在仅用于 UI 而不是实际值的情况下非常有用。 |
| index | Number | undefined | 如果父级是列表,允许在给定索引处插入输入。如果输入的值未定义,它将继承该索引位置的值。如果它有一个值,它将在给定索引处将其插入到列表的值中。 |
| label | String | '' | 与输入关联的 label 元素的文本。 |
| name | String | input_{n} | 输入的名称,在数据对象中唯一标识。在一组字段中应该是唯一的。 |
| parent | FormKitNode | contextual | 默认情况下,父级是包装组、列表或表单,但此属性允许显式分配父级节点。 |
| prefix-icon | String | '' | 指定放置在 prefixIcon 部分的 图标。 |
| preserve | boolean | false | 在输入卸载时,在父组、列表或表单上保留输入的值。 |
| preserve-errors | boolean | false | 默认情况下,使用 setErrors 在输入上设置的错误会在输入时自动清除,将此属性设置为 true 可以保留错误,直到明确清除为止。 |
| sections-schema | Object | {} | 一个包含部分键和模式部分值的对象,其中每个模式部分应用于相应的部分。 |
| suffix-icon | String | '' | 指定放置在 suffixIcon 部分的 图标。 |
| type | String | text | 要从库中渲染的输入类型。 |
| validation | String, Array | [] | 要应用于输入的 验证 规则。 |
| validation-visibility | String | blur | 确定何时显示输入的验证失败规则。有效值为 blur、dirty 和 live。 |
| validation-label | String | {label prop} | 确定在验证错误消息中使用的标签,默认情况下,如果可用,则使用 label 属性,否则使用 name 属性。 |
| validation-rules | Object | {} | 附加的自定义验证规则,可用于验证 prop。 |
| value | Any | undefined | 为输入和/或其子元素提供初始值。不是响应式的。可以种子 整个组(表单)和列表。 |
您可以使用该部分的“键”来定位输入的特定部分,从而允许您修改该部分的类,HTML(通过 :sections-schema),或内容(通过插槽)。在这里阅读更多关于部分的信息。
当添加 overlay 属性时,此部分位于 inner 部分内。
当日期选择器弹出窗口打开时,面板会出现在 inner 部分内的输入元素下方。
当日期选择器弹出窗口打开时,面板会出现在inner部分的输入元素下方。
当日期选择器弹出窗口打开时,面板会出现在inner部分的输入元素下方。
当日期选择器弹出窗口打开时,面板会出现在inner部分的输入元素下方。
| Section-key | 描述 |
|---|---|
| calendar | 日历面板上日历周围的包装器。 |
| calendarHeader | 日历面板上标题列周围的包装器。 |
| calendarWeeks | 日历面板上每行周围的包装器。 |
| day | 日的内容 - 默认包含数字日期。在此插槽/部分中,您可以使用context.day(在模式中为$day)获取给定日的日期对象。 |
| dayButton | 时间面板标题中显示的按钮,导航至日面板。 |
| dayCell | 日期部分周围的包装器。在此插槽/部分中,您可以使用context.day(在模式中为$day)获取给定日的日期对象。 |
| daysHeader | 日期面板上标题列周围的包装器。 |
| month | 在月面板上渲染实际月份名称的部分。在此插槽/部分中,您可以使用context.month(在模式中为$month)获取给定月份的日期对象。 |
| monthButton | 日和时间面板标题中的按钮,导航至月面板。 |
| months | 月面板上月份部分周围的包装器。 |
| monthsHeader | 月面板上标题按钮(yearButton)周围的包装器。 |
| next | 面板标题中负责导航至下一个月或十年的按钮。 |
| nextLabel | 负责渲染面板标题中下一个按钮的文本内容的部分。 |
| openButton | 负责打开选择器对话框的按钮。 |
| overlay | 覆盖层的外包装器。覆盖层用于模仿文本输入期间文本输入中的文本,以允许进行样式设置。 |
| overlayChar | 包含类型为char的覆盖字符的部分 |
| overlayEnum | 包含类型为enum的覆盖字符的部分 |
| overlayInner | 覆盖部分内部的内包装器。 |
| overlayLiteral | 包含类型为literal的覆盖字符的部分 |
| overlayParts | 包含所有覆盖部分作为直接子元素的部分。 |
| overlayPlaceholder | 包含类型为placeholder的覆盖字符的部分。 |
| panel | 当前活动面板周围的包装器。这是在panelHeader下面作为兄弟元素渲染的。 |
| panelHeader | 每个面板的标题周围的包装器,其中位于面板的导航按钮。这是面板部分的兄弟元素。 |
| panelWrapper | 面板和panelHeader部分周围的包装器,此部分负责显示或隐藏选择器对话框。 |
| prev | 面板标题中负责导航至上一个月或十年的按钮。 |
| prevLabel | 负责渲染面板标题中上一个按钮的文本内容的部分。 |
| time | 包含timeInput的时间面板。 |
| timeHeader | 时间面板的面板标题,有导航至年,月和日面板的按钮。 |
| timeInput | 一个原生HTML time 输入,负责设置选定日期的时间。 |
| week | 日面板上7天行周围的包装器。 |
| weekDay | 负责在日面板的日历标题中渲染一周中的某一天(M,T,W等)的单元格。 |
| weekDays | 日面板上日历标题中一周的天数周围的包装元素。 |
| year | 负责在年面板上渲染每年可用年份的元素。 |
| yearButton | 月,日和时间面板标题中的按钮,导航至年面板。 |
| years | 年份面板,负责一次渲染十年的年份。 |
| yearsHeader | 在年份面板上的面板标题,显示当前十年的年份范围。 |
| 显示 通用 section keys | |
| outer | 最外层的包装元素。 |
| wrapper | 标签和输入周围的包装器。 |
| label | 输入的标签。 |
| prefix | 默认情况下没有输出,但允许直接在输入元素之前放置内容。 |
| prefixIcon | 输出在前缀部分之前放置一个图标的元素。 |
| inner | 实际输入元素周围的包装器。 |
| suffix | 默认情况下没有输出,但允许直接在输入元素之后放置内容。 |
| suffixIcon | 输出在后缀部分之后放置一个图标的元素。 |
| input | 输入元素本身。 |
| help | 包含帮助文本的元素。 |
| messages | 包装所有消息的容器。 |
| message | 包含消息的元素(或多个元素) - 最常见的是验证和错误消息。 |