# RangeCalendar 范围日历 · HeroUI

> 基于 React Aria RangeCalendar 的可组合日期范围选择器，包含月份网格、导航与年份选择支持。

- 页面: https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar
- 改编自: HeroUI 文档 (Apache-2.0) @ 60edd8ed751b1d2a270623fbb182bbcfa8baa9af

## 引入

```tsx
import { RangeCalendar } from '@heroui/react';
```

### 用法


> 示例 `range-calendar-basic`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 组件结构

```tsx
import {RangeCalendar} from '@heroui/react';

export default () => (
  <RangeCalendar aria-label="Trip dates">
    <RangeCalendar.Header>
      <RangeCalendar.Heading />
      <RangeCalendar.NavButton slot="previous" />
      <RangeCalendar.NavButton slot="next" />
    </RangeCalendar.Header>
    <RangeCalendar.Grid>
      <RangeCalendar.GridHeader>
        {(day) => <RangeCalendar.HeaderCell>{day}</RangeCalendar.HeaderCell>}
      </RangeCalendar.GridHeader>
      <RangeCalendar.GridBody>
        {(date) => <RangeCalendar.Cell date={date} />}
      </RangeCalendar.GridBody>
    </RangeCalendar.Grid>
  </RangeCalendar>
)
```

### 年份选择

`RangeCalendar.YearPickerTrigger`、`RangeCalendar.YearPickerGrid` 及其 body/cell 子组件提供一体化的年份导航模式。


> 示例 `range-calendar-year-picker`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 默认值


> 示例 `range-calendar-default-value`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 受控


> 示例 `range-calendar-controlled`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 最小与最大日期


> 示例 `range-calendar-min-max-dates`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 不可用日期

使用 `isDateUnavailable` 禁用周末、节假日或已被预订的日期等。


> 示例 `range-calendar-unavailable-dates`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 基于锚点的不可用日期

选择范围时，`isDateUnavailable` 的第二个参数 `anchorDate` 为用户选中的开始日期。可据此限制结束日期（例如仅允许开始日期前后 7 天）。


> 示例 `range-calendar-anchor-unavailable-dates`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 固定周数

将 `weeksInMonth` 设为固定值（例如 `6`），可在月份切换时保持网格高度稳定。


> 示例 `range-calendar-weeks-in-month`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 周视图

设置 `visibleDuration={{ weeks: n }}` 可一次显示一个或多个周。翻页会按可见周范围前进。显示多周时可配合 `pageBehavior="single"` 每次仅移动一周。


> 示例 `range-calendar-week-view`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 日视图

设置 `visibleDuration={{ days: n }}` 可显示连续多天的滚动窗口。翻页会按可见天数范围前进。显示多天时配合 `pageBehavior="single"` 可每次仅移动一天。


> 示例 `range-calendar-day-view`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 允许非连续范围

启用 `allowsNonContiguousRanges`，允许选择跨越不可用日期的范围。


> 示例 `range-calendar-allows-non-contiguous-ranges`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 禁用


> 示例 `range-calendar-disabled`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 只读


> 示例 `range-calendar-read-only`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 无效


> 示例 `range-calendar-invalid`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 焦点日期


> 示例 `range-calendar-focused-value`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 单元格指示器

你可以自定义 `RangeCalendar.Cell` 的子节点，并使用 `RangeCalendar.CellIndicator` 展示活动等元数据。


> 示例 `range-calendar-with-indicators`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 多个月份

使用 `visibleDuration` 与 `offset` 渲染多个月份网格，适用于预订与规划场景。在各列头部为 `RangeCalendar.Heading` 设置 `offset`（例如 `offset={{ months: 1 }}`）以显示对应月份标题。


> 示例 `range-calendar-multiple-months`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


### 国际化历法

默认情况下，RangeCalendar 按用户语言环境的历法显示日期。你可以使用 `I18nProvider` 包裹 RangeCalendar，并通过 [Unicode 历法语言扩展](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string) 覆盖。

下方示例展示印度历法系统：


> 示例 `range-calendar-international-calendar`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


**说明：** `onChange` 事件始终返回与 `value` 或 `defaultValue` 相同历法系统中的日期（若未提供值则为公历），与界面展示的本地化格式无关。

### 实际场景示例


> 示例 `range-calendar-booking-calendar`: 交互预览见 https://jiguang132.com/zh/systems/heroui/docs/components/range-calendar


## 样式

### 传入 Tailwind CSS 类

```tsx
import {RangeCalendar} from '@heroui/react';

function CustomRangeCalendar() {
  return (
    <RangeCalendar aria-label="Trip dates" className="w-80 rounded-2xl border border-border bg-surface p-3 shadow-sm">
      <RangeCalendar.Header className="pb-3">
        <RangeCalendar.Heading className="text-default" />
        <RangeCalendar.NavButton slot="previous" className="text-default" />
        <RangeCalendar.NavButton slot="next" className="text-default" />
      </RangeCalendar.Header>
      <RangeCalendar.Grid>
        <RangeCalendar.GridHeader>
          {(day) => <RangeCalendar.HeaderCell>{day}</RangeCalendar.HeaderCell>}
        </RangeCalendar.GridHeader>
        <RangeCalendar.GridBody>
          {(date) => <RangeCalendar.Cell date={date} />}
        </RangeCalendar.GridBody>
      </RangeCalendar.Grid>
    </RangeCalendar>
  );
}
```

### 自定义组件类

```css
@layer components {
  .range-calendar {
    @apply w-80 rounded-2xl border border-border bg-surface p-3 shadow-sm;
  }

  .range-calendar__heading {
    @apply text-sm font-semibold text-default;
  }

  .range-calendar__cell[data-selected="true"] .range-calendar__cell-button {
    @apply bg-accent text-accent-foreground;
  }
}
```

### CSS 类

RangeCalendar 在 `packages/styles/components/range-calendar.css` 与 `packages/styles/components/calendar-year-picker.css` 中使用以下类：

- `.range-calendar` - 根容器。
- `.range-calendar__header` - 含导航按钮与标题的头部行。
- `.range-calendar__heading` - 当前月份标签。
- `.range-calendar__nav-button` - 上一月/下一月导航控件。
- `.range-calendar__grid` - 主体日期网格。
- `.range-calendar__grid-header` - 星期标题行外层。
- `.range-calendar__grid-body` - 日期行外层。
- `.range-calendar__header-cell` - 星期标题单元格。
- `.range-calendar__cell` - 可交互日期单元格外层。
- `.range-calendar__cell-button` - 单元格内的可交互日期按钮。
- `.range-calendar__cell-indicator` - 日期单元格内的圆点指示器。
- `.calendar-year-picker__trigger` - 年份选择器切换按钮。
- `.calendar-year-picker__trigger-heading` - 年份选择触发器内的标题文案。
- `.calendar-year-picker__trigger-indicator` - 年份选择触发器内的指示图标。
- `.calendar-year-picker__year-grid` - 可选年份的覆盖网格。
- `.calendar-year-picker__year-cell` - 单个年份选项。

### 交互状态

RangeCalendar 同时支持伪类与 React Aria 的 data 属性：

- **已选中**：`[data-selected="true"]`
- **范围起点**：`[data-selection-start="true"]`
- **范围终点**：`[data-selection-end="true"]`
- **范围内**：`[data-selection-in-range="true"]`
- **今天**：`[data-today="true"]`
- **不可用**：`[data-unavailable="true"]`
- **跨月**：`[data-outside-month="true"]`
- **悬停**：`:hover` 或 `[data-hovered="true"]`
- **按下**：`:active` 或 `[data-pressed="true"]`
- **焦点可见**：`:focus-visible` 或 `[data-focus-visible="true"]`
- **禁用**：`:disabled` 或 `[data-disabled="true"]`

## API 参考

### RangeCalendar Props

RangeCalendar 继承 React Aria [RangeCalendar](https://react-spectrum.adobe.com/react-aria/RangeCalendar.html) 的全部 props。

| Prop | 类型 | 默认值 | 描述 |
|------|------|--------|------|
| `value` | `RangeValue \| null` | - | 受控的选中范围。 |
| `defaultValue` | `RangeValue \| null` | - | 初始选中范围（非受控）。 |
| `onChange` | `(value: RangeValue) => void` | - | 选中变化时调用。 |
| `focusedValue` | `DateValue` | - | 受控的焦点日期。 |
| `onFocusChange` | `(value: DateValue) => void` | - | 焦点移动到其它日期时调用。 |
| `minValue` | `DateValue` | 历法感知的 `1900-01-01` | 可选的最早日期。 |
| `maxValue` | `DateValue` | 历法感知的 `2099-12-31` | 可选的最晚日期。 |
| `weeksInMonth` | `number` | - | 一个月的周数。该值会覆盖区域设置的默认值。 |
| `isDateUnavailable` | `(date: DateValue, anchorDate: CalendarDate \| null) => boolean` | - | 将日期标记为不可用。`anchorDate` 为当前范围选择中的首个日期。 |
| `firstDayOfWeek` | `'sun' \| 'mon' \| 'tue' \| 'wed' \| 'thu' \| 'fri' \| 'sat'` | - | 覆盖区域设置的一周起始日。 |
| `pageBehavior` | `'visible' \| 'single'` | `'visible'` | 翻页按可见范围或单步前进。 |
| `selectionAlignment` | `'start' \| 'center' \| 'end'` | `'center'` | 初始渲染时按选中项对齐可见范围。 |
| `allowsNonContiguousRanges` | `boolean` | `false` | 允许范围跨越不可用日期。 |
| `isDisabled` | `boolean` | `false` | 禁用交互与选择。 |
| `isReadOnly` | `boolean` | `false` | 内容只读，不可更改选中。 |
| `isInvalid` | `boolean` | `false` | 标记为无效以配合校验样式。 |
| `visibleDuration` | `{months?: number; weeks?: number; days?: number}` | `{months: 1}` | 可见时间范围。使用 `{ months: n }` 为月视图，`{ weeks: n }` 为周视图，`{ days: n }` 为日视图。 |
| `defaultYearPickerOpen` | `boolean` | `false` | 内置年份选择器的初始展开状态。 |
| `isYearPickerOpen` | `boolean` | - | 受控的年份选择器展开状态。 |
| `onYearPickerOpenChange` | `(isOpen: boolean) => void` | - | 年份选择器展开状态变化时调用。 |

### 组合部件

| 组件 | 描述 |
|-----------|-------------|
| `RangeCalendar.Header` | 导航与标题的头部容器。 |
| `RangeCalendar.Heading` | 可见范围的格式化标题。支持 `offset`（多月份布局）与 `format`（月/年/日格式选项）。 |
| `RangeCalendar.NavButton` | 上一页/下一页导航（`slot="previous"` 或 `slot="next"`）。 |
| `RangeCalendar.Grid` | 单个月的日期网格（多月份布局支持 `offset`）。 |
| `RangeCalendar.GridHeader` | 星期标题容器。 |
| `RangeCalendar.GridBody` | 日期单元格主体容器。 |
| `RangeCalendar.HeaderCell` | 星期标签单元格。 |
| `RangeCalendar.Cell` | 单个日期单元格。 |
| `RangeCalendar.CellIndicator` | 用于自定义元数据的可选指示元素。 |
| `RangeCalendar.YearPickerTrigger` | 切换年份选择模式的触发器。 |
| `RangeCalendar.YearPickerTriggerHeading` | 年份选择触发器内的本地化标题内容。 |
| `RangeCalendar.YearPickerTriggerIndicator` | 年份选择触发器内的切换图标。 |
| `RangeCalendar.YearPickerGrid` | 年份选择覆盖网格容器。 |
| `RangeCalendar.YearPickerGridBody` | 年份网格单元格的 body 渲染器。 |
| `RangeCalendar.YearPickerCell` | 单个年份选项单元格。 |

### 年份选择器子组件

年份选择器子组件继承 React Aria [`useCalendarHeading`](https://react-aria.adobe.com/useCalendar#usecalendarheading) 与 [`useCalendarYearPicker`](https://react-aria.adobe.com/useCalendar#usecalendaryearpicker) 的格式化属性。

| 组件 | 属性 | 类型 | 默认值 | 描述 |
|------|------|------|--------|------|
| `RangeCalendar.YearPickerTriggerHeading` | `format` | `DateFormatterOptions` | - | 自定义月/年标题（如 `{month: 'short'}`）。 |
| `RangeCalendar.YearPickerTriggerHeading` | `offset` | `{months?: number}` | - | 相对聚焦日期偏移标题（多月布局）。 |
| `RangeCalendar.YearPickerGrid` | `format` | `DateFormatterOptions` | `{year: 'numeric'}` | 自定义年份单元格标签（纪元、历法系统等）。 |
| `RangeCalendar.YearPickerGrid` | `visibleYears` | `number` | min–max 跨度或 `20` | 滑动窗口中显示的年份数量。当同时设置 `minValue` 与 `maxValue` 时，默认为二者之间的完整范围。 |

### RangeCalendar.Cell Render Props

当 `RangeCalendar.Cell` 的 `children` 为函数时，可使用 React Aria 的渲染参数：

| Prop | 类型 | 描述 |
|------|------|------|
| `formattedDate` | `string` | 单元格日期的本地化文案。 |
| `isSelected` | `boolean` | 该日期是否已选中。 |
| `isSelectionStart` | `boolean` | 是否为选中范围的起点。 |
| `isSelectionEnd` | `boolean` | 是否为选中范围的终点。 |
| `isUnavailable` | `boolean` | 该日期是否不可用。 |
| `isDisabled` | `boolean` | 单元格是否禁用。 |
| `isOutsideMonth` | `boolean` | 是否属于相邻月份。 |

支持的历法系统及其标识符完整列表见：
- [React Aria Calendar Implementations](https://react-aria.adobe.com/internationalized/date/Calendar#implementations)
- [React Aria International Calendars](https://react-aria.adobe.com/Calendar#international-calendars)

### Related packages

- [`@internationalized/date`](https://react-aria.adobe.com/internationalized/date/) — 各日期组件共用的日期类型（`CalendarDate`、`CalendarDateTime`、`ZonedDateTime`）与工具函数
- [`I18nProvider`](https://react-aria.adobe.com/I18nProvider) — 为子树覆盖语言环境
- [`useLocale`](https://react-aria.adobe.com/useLocale) — 读取当前语言环境与书写方向

---

JGuang 全部资源索引: https://jiguang132.com/llms.txt
