☰
Ant Design Blazor Calendar 日历组件完整实战指南:API 参数、单元格渲染与源码原理
2026/10/10 11:28:49 网站建设 项目流程
  • UI组件
  • 前端

【免费下载链接】ant-design-blazor

🌈A rich set of enterprise-class UI components based on Ant Design and Blazor.

项目地址:https://gitcode.com/gh_mirrors/an/ant-design-blazor
点击查看免费下载

导读

本文围绕 ant-design-blazor 仓库中的 Calendar 组件文档 展开,系统讲解日历组件的适用场景、全部 API 参数、事件回调与国际化注意事项,并结合仓库源码与官方示例深入剖析dateCellRender、monthCellRender、headerRender等高级自定义能力的实现原理。读完本文,你将掌握如何用<Calendar>组件快速搭建日程、课表、价格日历等按日期划分的数据展示容器,并能按需定制日期单元格内容、切换年/月面板甚至完全重写日历头部。

何时使用 Calendar 组件

Calendar是"按照日历形式展示数据的容器"。当业务数据本身是日期、或者天然按照日期划分时,就适合使用它,典型场景包括:

  • 日程/事件列表:每天展示若干条提醒或事件;
  • 课表:按日期维度呈现课程安排;
  • 价格日历:在日期格内展示当天价格;
  • 农历等历法信息:在日期格内追加农历等附加数据。

组件目前支持年/月两种面板模式切换,配合自定义渲染函数即可在单元格内叠加任意内容。组件类定义位于 components/calendar/Calendar.razor.cs,其文档注释与官方文档保持一致:"Container for displaying data in calendar form."。

基本用法:一个开箱即用的日历面板

最简单的用法是直接声明<Calendar />,即可得到一个支持年/月切换的通用日历面板。官方示例 Basic.razor 展示了绑定面板切换事件的基本写法:

<Calendar OnPanelChange="OnPanelChange" /> @code { private void OnPanelChange(DateTime value, DatePickerType type) { Console.WriteLine($"{value.ToString("yyyy-MM-dd")} {type}"); } }

OnPanelChange在用户切换年/月视图(即面板变化)时触发,回调参数为当前面板代表日期(DateTime)与面板类型(DatePickerType)。注意DatePickerType定义在 components/date-picker/types 目录中,它同时被日期选择器与日历组件共用,用于标识日期粒度(如Date、Month)。

API 参数全解

以下参数表完整继承自官方文档 index.zh-CN.md,并结合源码实现逐项补充了默认值与行为细节:

参数说明类型默认值
dateCellRender自定义渲染日期单元格,返回内容会被追加到单元格Func<DateTime, RenderFragment>无
dateFullCellRender自定义渲染日期单元格,返回内容覆盖单元格Func<DateTime, RenderFragment>无
defaultValue默认展示的日期DateTime默认日期
disabledDate不可选择的日期Func<DateTime, bool>无
fullscreen是否全屏显示booltrue
locale国际化配置(TODO)DatePickerLocale全局 Locale 的 DatePicker 配置
mode初始模式,CalendarMode.Month/CalendarMode.YearCalendarModeCalendarMode.Month
monthCellRender自定义渲染月单元格,返回内容会被追加到单元格Func<DateTime, RenderFragment>无
monthFullCellRender自定义渲染月单元格,返回内容覆盖单元格Func<DateTime, RenderFragment>无
validRange设置可以显示的日期范围DateTime[](两个元素)无
value展示日期DateTime当前日期
onPanelChange日期面板变化回调Action<DateTime, DatePickerType>无
onSelect点击选择日期回调(已标记 Obsolete,建议改用 onChange)EventCallback<DateTime>无
onChange日期变化回调EventCallback<DateTime>无
headerRender自定义头部内容Func<CalendarHeaderRenderArgs, RenderFragment>无

value 与 defaultValue

源码中 Value 参数 默认值为DateTime.Now,表示当前展示的日期;DefaultValue 参数 的 setter 在赋值时会同步覆盖Value,因此二者是联动关系——设置DefaultValue等价于同时设置了初始展示日期:

public DateTime DefaultValue { get => _defaultValue; set { _defaultValue = value; Value = _defaultValue; // 同步写入 Value } }

fullscreen 全屏与卡片模式

FullScreen默认true,即日历占据父容器全部可用宽度。当它设置为false时,日历会以紧凑卡片形态呈现,适合嵌套在空间有限的容器中(如侧边栏面板)。对应 CSS 类映射在 SetClass 方法 中:FullScreen = true时追加ant-picker-calendar-full类,false时不追加。

官方示例 Card_.razor 展示了卡片模式,将日历放入一个 300px 宽的带边框容器中:

<div class="site-calendar-demo-card"> <Calendar FullScreen="@false" OnPanelChange="OnPanelChange" /> </div>

disabledDate 禁用日期

disabledDate接收一个Func<DateTime, bool>委托,返回true的日期将不可选择。该参数在 Calendar.razor.cs 中声明,默认值为null(即全部日期可选),可直接在 Razor 中传入 Lambda:

<Calendar DisabledDate="date => date.DayOfWeek == DayOfWeek.Sunday" />

validRange 可显示范围

validRange为DateTime[](两个元素的数组,分别表示起止日期),用于限定日历中可显示的日期区间。值得注意的源码细节:在 OnInitialized 方法 中,初始化时会检查当前Value是否越界——若Value小于范围下界则钳制到下界,大于上界则钳制到上界,确保初始展示日期始终落在合法范围内:

if (ValidRange != null) { if (Value < ValidRange[0]) { Value = ValidRange[0]; } else if (Value > ValidRange[1]) { Value = ValidRange[1]; } }

mode 初始模式

mode决定日历初始展示的是月份面板(CalendarMode.Month,即逐日视图)还是年份面板(CalendarMode.Year,即逐月视图),默认CalendarMode.Month。枚举定义见 CalendarMode.cs。源码中 Mode 会被映射为日期选择器的面板粒度:Month → DatePickerType.Date、Year → DatePickerType.Month(见 OnInitialized),并由内部组件 CalendarPanelChooser 负责实际渲染对应粒度的面板。

locale 国际化与 moment locale 前置条件

官方文档特别提醒:Calendar 部分 locale 是从 value(日期值)中读取的,因此请先正确设置 moment 的 locale。默认语言为en-US,若需使用其他语言,推荐在应用入口文件全局设置 locale,例如:

// import moment from 'moment'; // import 'moment/locale/zh-cn'; // moment.locale('zh-cn');

在源码层面,Locale 参数 的类型为DatePickerLocale,其默认值取自全局LocaleProvider.CurrentLocale.DatePicker;同时组件还暴露了 CultureInfo 参数(默认取LocaleProvider.CurrentLocale.CurrentCulture),用于日期格式化——例如 GetFormatValue 方法 即以该 CultureInfo 格式化日期字符串。因此,要获得正确的中文月名、周起始日等展示效果,需要在初始化时同步配置 moment locale 与项目的 LocaleProvider。仓库各语言资源位于 components/locales(如 zh-CN.json),可供参考。

事件回调机制:onSelect、onChange 与 onPanelChange

组件内部点击日期时统一走 OnSelectValue 方法,其调用链清晰揭示了三个事件的关系:

protected void OnSelectValue(DateTime date) { Value = date; // 1. 更新当前值 OnSelect.InvokeAsync(date); // 2. 触发 onSelect OnChange.InvokeAsync(date); // 3. 触发 onChange StateHasChanged(); }
  • onSelect:点击选择日期时触发。源码中该参数已标注[Obsolete("Use OnChange instead")](Calendar.razor.cs),官方建议新代码改用onChange;
  • onChange:日期变化时触发(点击选择同样会触发),是当前推荐的选择回调;
  • onPanelChange:仅当用户在年月面板之间切换时触发(见下方 ChangeMode)。

ChangeMode:面板切换的底层实现

当用户点击头部切换视图时,ChangeMode 方法 会完成模式更新、记录前一个面板类型(_prePickerStack用于回退)并触发OnPanelChange回调:

internal void ChangeMode(CalendarMode mode) { Mode = mode; DatePickerType picker = Mode switch { CalendarMode.Month => DatePickerType.Date, CalendarMode.Year => DatePickerType.Month, _ => DatePickerType.Date }; _prePickerStack.Push(_picker); _picker = picker; OnPanelChange?.Invoke(PickerValues[0], _picker); StateHasChanged(); }

自定义日期/月份单元格:dateCellRender 与 monthCellRender

日历组件最核心的扩展点就是四个单元格渲染函数。理解"追加"与"覆盖"的区别至关重要:

  • dateCellRender/monthCellRender:返回的RenderFragment会被追加到单元格默认内容之后;
  • dateFullCellRender/monthFullCellRender:返回内容会整体覆盖单元格(包括默认的日期数字)。

两者均接收DateTime参数,代表当前要渲染的日期/月份。

官方示例 NoticeCalendar.razor 是经典的事件日历实现:按日期维护一份事件列表,用dateCellRender在日期格内追加 Badge 事件条目,用monthCellRender在月份格内追加"Backlog number"统计数字:

<Calendar DateCellRender="DateCellRender" MonthCellRender="MonthCellRender" /> @code { private RenderFragment DateCellRender(DateTime value) { var listData = GetListData(value); // 按 value.Day 返回当天事件列表 return @<Template> <ul class="events"> @foreach (var data in listData) { <li key="@data.content"> <Badge Status="@data.type" Text="@data.content" /> </li> } </ul> </Template>; } private RenderFragment MonthCellRender(DateTime value) { int? num = GetMonthData(value); // 如 8 月返回 1394 if (num == null) return null; return @<Template> <div className="notes-month"> <section>@num</section> <span>Backlog number</span> </div> </Template>; } }

该示例同时展示了组件与 Badge 的组合用法:将BadgeStatus(Warning/Success/Error)映射为徽标状态,在日期格内呈现事件语义。参考样式.events与.notes-month位于同一示例文件末尾的<Style>块中,用于控制事件列表的溢出省略与月份统计的居中排版。

自定义头部:headerRender

headerRender允许完全替换日历顶部的年月切换区域,其参数类型为CalendarHeaderRenderArgs(定义见 CalendarHeaderRenderCallback.cs),包含四个成员:

成员类型说明
ValueDateTime当前面板代表日期
TypeCalendarMode当前模式(Month / Year)
OnChangeAction<DateTime>变更日期的回调(切换年/月后调用)
OnTypeChangeAction<CalendarMode>变更模式回调(切换 Month/Year 面板)

组件模板逻辑见 Calendar.razor:当HeaderRender不为 null 时直接调用自定义头部;否则渲染内置的CalendarHeader组件。

官方示例 CustomizeHeader.razor 实现了一个"标题 + RadioGroup 模式切换 + 年份下拉 + 月份下拉"的完全自定义头部,其中调用args.OnTypeChange与args.OnChange驱动组件内部状态的关键代码如下:

<Calendar FullScreen="@false" HeaderRender="HeaderRender" OnPanelChange="OnPanelChange" /> @code { private RenderFragment HeaderRender(CalendarHeaderRenderArgs args) { int month = args.Value.Month; int year = args.Value.Year; return @<Template> <div style="padding: 8px"> <Title Level="4">Custom header</Title> <Row Gutter="8"> <AntDesign.Col> <RadioGroup Size="InputSize.Small" OnChange="value => args.OnTypeChange(value)" Value="@args.Type" TValue="CalendarMode"> <Radio RadioButton Value="CalendarMode.Month">Month</Radio> <Radio RadioButton Value="CalendarMode.Year">Year</Radio> </RadioGroup> </AntDesign.Col> <AntDesign.Col> <select @onchange="e => OnSelectYear(e, args)" value="@year"> @GetYearOptions(year) </select> </AntDesign.Col> <AntDesign.Col> <select @onchange="e => OnSelectMonth(e, args)" value="@month"> @GetMonthOptions() </select> </AntDesign.Col> </Row> </div> </Template>; } private void OnSelectYear(ChangeEventArgs args, CalendarHeaderRenderArgs renderArgs) { int year = Convert.ToInt32(args.Value); renderArgs.OnChange(DateHelper.CombineNewDate(renderArgs.Value, year: year)); } private void OnSelectMonth(ChangeEventArgs args, CalendarHeaderRenderArgs renderArgs) { int month = Convert.ToInt32(args.Value); renderArgs.OnChange(DateHelper.CombineNewDate(renderArgs.Value, month: month)); } }

注意示例中通过DateHelper.CombineNewDate(工具类定义于 components/core/Helpers)在保留原日期其他字段的基础上合成新日期,再传给OnChange,从而驱动面板日期更新。头部内的OnTypeChange会最终路由到源码中的ChangeMode,触发OnPanelChange回调。

源码级原理小结

将文档 API 与源码 Calendar.razor.cs 对照,可以归纳出组件设计的几个关键机制:

  1. 面板粒度映射:CalendarMode.Month/Year与DatePickerType.Date/Month一一对应,组件复用日期选择器的面板渲染体系(内部使用CalendarPanelChooser,见 Calendar.razor);
  2. 值联动:DefaultValue的 setter 同步写入Value,ValidRange在初始化时对Value做越界钳制;
  3. 回调分层:点击日期统一经过OnSelectValue,同时触发OnSelect(已废弃)与OnChange;面板切换单独走ChangeMode并触发OnPanelChange,且用_prePickerStack栈记录面板切换历史以支持回退;
  4. 渲染扩展点:头部可由HeaderRender完全接管(CalendarHeaderRenderArgs提供值、模式与两个驱动回调),单元格则由追加式(dateCellRender/monthCellRender)与覆盖式(dateFullCellRender/monthFullCellRender)两类委托提供两级自定义能力;
  5. 国际化依赖:locale 从日期值与全局LocaleProvider.CurrentLocale读取,使用前需正确配置 moment locale(默认 en-US)。

实战建议

  • 日程/事件日历:优先使用dateCellRender+ Badge 组合,事件数据按日期分组后在单元格内追加展示;
  • 价格日历/课表:若需要完全掌控单元格内容(隐藏默认日期数字),使用dateFullCellRender/monthFullCellRender覆盖式渲染;
  • 嵌入窄容器:设置FullScreen="@false"并配合自定义容器宽度(参考 Card_.razor 的 300px 卡片写法);
  • 品牌化头部:通过headerRender重写年月切换器,可在其中混合使用 RadioGroup、Select 等组件与原生<select>;
  • 注意 API 演进:onSelect已标记[Obsolete],新代码应统一使用onChange响应日期选择。
  • UI组件
  • 前端

【免费下载链接】ant-design-blazor

🌈A rich set of enterprise-class UI components based on Ant Design and Blazor.

项目地址:https://gitcode.com/gh_mirrors/an/ant-design-blazor
点击查看免费下载
上一篇:智能姿态标注实战指南:开源工具的高效应用与性能优化
下一篇:CHOC跨平台开发终极指南:Windows、macOS、Linux统一接口设计

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

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

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

立即咨询