Lzh on GitHub

Range Calendar

提供适合选择日期范围的日历视图。
<script setup lang="ts">
import type { DateValue } from '@internationalized/date'
import { Icon } from '@iconify/vue'
import { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNext, RangeCalendarPrev, RangeCalendarRoot } from 'reka-ui'

function isDateUnavailable(date: DateValue) {
  return date.day === 17 || date.day === 18
}
</script>

<template>
  <RangeCalendarRoot
    v-slot="{ weekDays, grid }"
    :is-date-unavailable="isDateUnavailable"
    class="rounded-xl bg-white p-4 shadow-sm border"
    fixed-weeks
  >
    <RangeCalendarHeader class="flex items-center justify-between">
      <RangeCalendarPrev
        class="inline-flex items-center cursor-pointer text-black justify-center rounded-md bg-transparent w-7 h-7 hover:bg-stone-50 active:scale-98 active:transition-all focus:shadow-[0_0_0_2px] focus:shadow-black"
      >
        <Icon
          icon="radix-icons:chevron-left"
          class="w-4 h-4"
        />
      </RangeCalendarPrev>
      <RangeCalendarHeading class="text-sm text-black font-medium" />
      <RangeCalendarNext
        class="inline-flex items-center cursor-pointer justify-center text-black rounded-md bg-transparent w-7 h-7 hover:bg-stone-50 active:scale-98 active:transition-all focus:shadow-[0_0_0_2px] focus:shadow-black"
      >
        <Icon
          icon="radix-icons:chevron-right"
          class="w-4 h-4"
        />
      </RangeCalendarNext>
    </RangeCalendarHeader>
    <div
      class="flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0"
    >
      <RangeCalendarGrid
        v-for="month in grid"
        :key="month.value.toString()"
        class="w-full border-collapse select-none space-y-1"
      >
        <RangeCalendarGridHead>
          <RangeCalendarGridRow class="mb-1 grid w-full grid-cols-7">
            <RangeCalendarHeadCell
              v-for="day in weekDays"
              :key="day"
              class="rounded-md text-xs text-green-800"
            >
              {{ day }}
            </RangeCalendarHeadCell>
          </RangeCalendarGridRow>
        </RangeCalendarGridHead>
        <RangeCalendarGridBody class="grid">
          <RangeCalendarGridRow
            v-for="(weekDates, index) in month.rows"
            :key="`weekDate-${index}`"
            class="grid grid-cols-7"
          >
            <RangeCalendarCell
              v-for="weekDate in weekDates"
              :key="weekDate.toString()"
              :date="weekDate"
            >
              <RangeCalendarCellTrigger
                :day="weekDate"
                :month="month.value"
                class="relative flex items-center justify-center rounded-full whitespace-nowrap text-sm font-normal text-black w-8 h-8 outline-none focus:shadow-[0_0_0_2px] focus:shadow-black data-[outside-view]:text-black/30 data-[selected]:!bg-green-900 data-[selected]:text-white hover:bg-green-500 data-[highlighted]:bg-green-500 data-[unavailable]:pointer-events-none data-[unavailable]:text-black/30 data-[unavailable]:line-through before:absolute before:top-[5px] before:hidden before:rounded-full before:w-1 before:h-1 before:bg-white data-[today]:before:block data-[today]:before:bg-green-900 "
              />
            </RangeCalendarCell>
          </RangeCalendarGridRow>
        </RangeCalendarGridBody>
      </RangeCalendarGrid>
    </div>
  </RangeCalendarRoot>
</template>

功能特性 (Features)

  • 完整的键盘导航。
  • 可控或非控。
  • 焦点完全管理。
  • 支持本地化。
  • 高度可组合。

前言 (Preface)

该组件依赖于 @internationalized/date 包,它解决了 JavaScript 中处理日期和时间所带来的许多问题。

我们强烈建议您阅读该包的文档,以充分了解其工作原理。您需要在项目中安装它才能使用日期相关的组件。

安装

安装日期包 (Install the date package)

$ npm add @internationalized/date

安装组件 (Install the component)

$ npm add reka-ui

结构 (Anatomy)

导入所有部件并将其组合在一起。

<script setup>
import {
  RangeCalendarCell,
  RangeCalendarCellTrigger,
  RangeCalendarGrid,
  RangeCalendarGridBody,
  RangeCalendarGridHead,
  RangeCalendarGridRow,
  RangeCalendarHeadCell,
  RangeCalendarHeader,
  RangeCalendarHeading,
  RangeCalendarNext,
  RangeCalendarPrev,
  RangeCalendarRoot
} from 'reka-ui'
</script>

<template>
  <RangeCalendarRoot>
    <RangeCalendarHeader>
      <RangeCalendarPrev />
      <RangeCalendarHeading />
      <RangeCalendarNext />
    </RangeCalendarHeader>
    <RangeCalendarGrid>
      <RangeCalendarGridHead>
        <RangeCalendarGridRow>
          <RangeCalendarHeadCell />
        </RangeCalendarGridRow>
      </RangeCalendarGridHead>
      <RangeCalendarGridBody>
        <RangeCalendarGridRow>
          <RangeCalendarCell>
            <RangeCalendarCellTrigger />
          </RangeCalendarCell>
        </RangeCalendarGridRow>
      </RangeCalendarGridBody>
    </RangeCalendarGrid>
  </RangeCalendarRoot>
</template>

API 参考 (API Reference)

根 (Root)

包含日历的所有部分。

属性默认值类型描述
allowNonContiguousRangesfalsebooleanisDateUnavailable 结合使用时,确定是否可以选择不连续范围(即包含不可用日期的范围)。
as'div'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。
calendarLabelstring日历的可访问标签。
defaultPlaceholderDateValue默认占位符日期。
defaultValue{ start: undefined, end: undefined }DateRange日历的默认值。
dir'ltr' | 'rtl'日历的阅读方向(如果适用)。如果省略,则全局继承自 ConfigProvider 或假定为 LTR(从左到右)阅读模式。
disabledfalseboolean日历是否禁用。
disableDaysOutsideCurrentViewfalseboolean是否禁用当前视图之外的日期。
fixedDate'start' | 'end'范围的哪一部分应固定。
fixedWeeksfalseboolean日历是否始终显示 6 周。
initialFocusfalseboolean如果为 true,则日历挂载时将根据可见内容聚焦选定的日期、今天或当月的第一天。
isDateDisabledMatcher返回日期是否被禁用的函数。
isDateHighlightableMatcher返回日期是否可高亮的函数。
isDateUnavailableMatcher返回日期是否不可用的函数。
localestring用于格式化日期的区域设置。
maximumDaysnumber可以在范围内选择的最大天数。
maxValueDateValue可选择的最大日期。
minValueDateValue可选择的最小日期。
modelValueDateRange | null日历的受控选中状态。可绑定为 v-model
nextPage((placeholder: DateValue) => DateValue)返回日历下一页的函数。它在组件内部接收当前占位符作为参数。
numberOfMonths1number一次显示的月份数量。
pagedNavigationfalseboolean此属性使“上一页”和“下一页”按钮根据一次显示的月份数量而不是一个月进行导航。
placeholderDateValue占位符日期,用于在未选择日期时确定要显示的月份。它会随着用户导航日历而更新,可用于编程控制日历视图。
preventDeselectfalseboolean是否阻止用户在未选择另一个日期的情况下取消选择日期。
prevPage((placeholder: DateValue) => DateValue)返回日历上一页的函数。它在组件内部接收当前占位符作为参数。
readonlyfalseboolean日历是否只读。
weekdayFormat'narrow''narrow' | 'short' | 'long'用于通过 weekdays 插槽提供的星期几字符串的格式。
weekStartsOn00 | 1 | 2 | 3 | 4 | 5 | 6日历开始的星期几。

发送事件

事件Payload描述
update:modelValue[date: DateRange]modelValue 更改时调用的事件处理程序。
update:placeholder[date: DateValue]placeholder 值更改时调用的事件处理程序。
update:startValue[date: DateValue]startValue 更改时调用的事件处理程序。

默认插槽

插槽参数插槽参数类型描述
dateDateValue占位符的当前日期。
gridGrid<DateValue>[]日期网格。
weekDaysstring[]星期几。
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6一周的开始。
localestring日历区域设置。
fixedWeeksboolean是否始终显示 6 周。
modelValueDateRange当前日期范围。

方法 (Methods)

方法名称类型描述
isDateDisabledMatcher返回日期是否被禁用的函数。
isDateUnavailableMatcher返回日期是否不可用的函数。
isDateHighlightableMatcher返回日期是否可高亮的函数。

数据属性 (Data Attribute)

描述
[data-readonly]只读时存在
[data-disabled]禁用时存在
[data-invalid]无效时存在

头部 (Header)

包含导航按钮和标题段。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

上一页按钮 (Prev Button)

日历导航按钮。它根据当前日历视图将日历向前导航一个月/年/十年。

数据属性 (Data Attribute)

描述
[data-disabled]禁用时存在
属性默认值类型描述
as'button'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。
prevPage((placeholder: DateValue) => DateValue)用于上一页的函数。覆盖 RangeCalendarRoot 上设置的 prevPage 函数。

默认插槽

插槽参数插槽参数类型描述
disabledboolean当前禁用状态

下一页按钮 (Next Button)

日历导航按钮。它根据当前日历视图将日历向后导航一个月/年/十年。

属性默认值类型描述
as'button'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。
nextPage((placeholder: DateValue) => DateValue)用于下一页的函数。覆盖 RangeCalendarRoot 上设置的 nextPage 函数。

默认插槽

插槽参数插槽参数类型描述
disabledboolean当前禁用状态

数据属性 (Data Attribute)

描述
[data-disabled]禁用时存在

标题 (Heading)

显示当前月份和年份的标题。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

默认插槽

插槽参数插槽参数类型描述
headingValuestring当前月份和年份。

数据属性 (Data Attribute)

描述
[data-disabled]禁用时存在

网格 (Grid)

用于包裹日历网格的容器。

属性默认值类型描述
as'table'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

数据属性 (Data Attribute)

描述
[data-readonly]只读时存在
[data-disabled]禁用时存在

网格头部 (Grid Head)

用于包裹网格头部的容器。

属性默认值类型描述
as'thead'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

网格体 (Grid Body)

用于包裹网格主体的容器。

属性默认值类型描述
as'tbody'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

网格行 (Grid Row)

用于包裹网格行的容器。

属性默认值类型描述
as'tr'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

头部单元格 (Head Cell)

用于包裹头部单元格的容器。用于显示星期几。

属性默认值类型描述
as'th'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。

单元格 (Cell)

用于包裹日历单元格的容器。

属性默认值类型描述
as'td'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。
date*DateValue日期。

数据属性 (Data Attribute)

描述
[data-disabled]禁用时存在

单元格触发器 (Cell Trigger)

用于显示单元格日期的可交互容器。点击它会选择日期。

属性默认值类型描述
as'div'AsTag | Component此组件应渲染为的元素或组件。可通过 asChild 覆盖。
asChildboolean将默认渲染的元素替换为作为子元素传递的元素,合并它们的 props 和行为。阅读我们的组合指南了解更多详情。
day*DateValue日。
month*DateValue月。

默认插槽

插槽参数插槽参数类型描述
dayValuestring当前日期。
disabledboolean当前禁用状态。
selectedboolean当前选中状态。
todayboolean当前是否为今天。
outsideViewboolean当前是否在当前月份视图之外。
outsideVisibleViewboolean当前是否在日历可见月份之外。
unavailableboolean当前是否不可用。
highlightedboolean当前是否被高亮。
highlightedStartboolean当前是否是高亮范围的开始。
highlightedEndboolean当前是否是高亮范围的结束。
selectionStartboolean当前是否是选中范围的开始。
selectionEndboolean当前是否是选中范围的结束。

数据属性 (Data Attribute)

描述
[data-selected]选中时存在
[data-value]日期的 ISO 字符串值。
[data-disabled]禁用时存在
[data-unavailable]不可用时存在
[data-today]今天时存在
[data-outside-view]日期在当前月份视图之外时存在。
[data-outside-visible-view]日期在日历可见月份之外时存在。
[data-selection-start]日期是选中范围的开始时存在。
[data-selection-end]日期是选中范围的结束时存在。
[data-highlighted]日期被用户高亮为范围时存在。
[data-highlighted-start]日期是用户高亮范围的开始时存在。
[data-highlighted-end]日期是用户高亮范围的结束时存在。
[data-focused]聚焦时存在

可访问性 (Accessibility)

键盘交互 (Keyboard Interactions)

按键描述
Tab当焦点移动到日历上时,聚焦第一个导航按钮。
Space当焦点位于 CalendarNextCalendarPrev 上时,导航日历。否则,选择日期。
Enter当焦点位于 CalendarNextCalendarPrev 上时,导航日历。否则,选择日期。
ArrowLeft ArrowRight ArrowUp ArrowDown当焦点位于 CalendarCellTrigger 上时,导航日期,必要时更改月份/年份/十年。