FullCalendar 的资源时间轴和按资源分列的视图属于 Premium 版:商业应用需要付费购买许可证密钥。它的许可证页面列出了可以免费使用的情形:整个应用都采用 AGPL,或者由已注册的非营利组织使用。Needless UI 日程表在 MIT 许可证下同时提供这两项功能,还支持重复日程和 iCalendar 文件。本指南介绍如何把 Angular 应用从前者迁移到后者:哪些可以直接沿用,哪些不行,以及哪些数据需要转换。
文中使用 FullCalendar 7 的名称;版本 6 的名称与之不同时,写在方括号中。FullCalendar 的 Angular 连接器支持 Angular 16 到 22;Needless UI 需要 Angular 22。
功能对比
| 功能 | FullCalendar | Needless UI |
|---|---|---|
| 资源时间轴:每个会议室或每个人各占一行 | Premium | 支持:一天、一周或一个月 |
| 日视图和周视图中按资源分列 | Premium | 支持 |
| 月、周、日视图 | 免费 | 支持 |
| 拖动来移动日程或调整时长 | 免费;拖到另一个资源上需要 Premium | 支持,也能拖到其他资源上。可以拖动结束端调整时长,开始端不行。 |
| 选择时间来创建日程 | 免费 | 支持,可用指针、长按或键盘 |
| 规则,例如不允许重叠 | 免费:overlap 和 constraint 选项 | 支持:只需一个 allow 函数,每次变更前都会询问它 |
| 用键盘移动日程、调整时长 | 其无障碍文档中没有提到;文档只涉及 ARIA 标签和 Tab 焦点 | 支持,并会向屏幕阅读器播报 |
| 重复日程 | 免费,需配合 rrule 插件和库 | 内置:RFC 5545 规则,但不支持 EXRULE、RDATE 和按小时重复的规则 |
| iCalendar(.ics) | 免费:可读取订阅源 | 可读写 .ics 文件 |
| 列表视图和年视图 | 免费 | 提供未来几天的日程列表;没有年视图 |
| 时区 | 免费:本地时区、UTC 或命名时区 | 不支持:按收到的时间原样显示 |
| 分组、嵌套或多列的资源 | Premium | 不支持:只有一列,由你的模板绘制 |
| 外部拖放、背景日程 | 免费 | 不支持 |
| 打印、虚拟渲染 | Premium | 不支持 |
| 框架 | Angular 16 到 22、React、Vue、纯 JavaScript 等 | Angular 22 和 React 19 |
选项对照
| FullCalendar | Needless UI 日程表 |
|---|---|
<full-calendar [options]>、plugins、schedulerLicenseKey | <nui-scheduler>,每个选项都有对应的输入属性;不需要插件,也不需要密钥 |
initialView: 'resourceTimelineDay' | view="timeline",按周或按月显示时再加上 timelineSpan |
initialView: 'timeGridWeek' | view="week";[(view)] 支持双向绑定 |
resources、events | [resources]、[events] |
resourceId、extendedProps | resource、data |
editable、selectable | editable、selectable |
select | (slotSelect):{ start, end, allDay, resource } |
eventDrop、eventResize | (eventChange):在你更新 events 之前,什么都不会移动 |
eventClick | (eventClick) |
eventOverlap、selectOverlap、eventAllow | [allow]:用一个函数统一处理移动、调整时长和选择 |
slotDuration、snapDuration | slotMinutes、snapMinutes,以分钟为单位 |
slotMinTime、slotMaxTime、scrollTime | dayStart、dayEnd、scrollHour,以小时为单位 |
businessHours | [businessHours],星期用 1(星期一)到 7 表示 |
datesSet | (rangeChange) |
eventContent、resourceCellContent [resourceLabelContent] | nuiSchedulerEvent 和 nuiSchedulerResource 模板 |
locale、firstDay | locale(任意 BCP 47 语言标签)、firstDay(取值 1 到 7),以及用于界面文字的 labels |
会议室预订时间轴的两种写法
会议室是资源,预订是日程。用户在会议室的行上拖动来预订,拖动预订来移动它,并且一个会议室同一时间只能有一个预订。使用 FullCalendar 7 及其 Premium 资源时间轴:
使用 Needless UI 日程表:
有两点不同。FullCalendar 会自行移动预订,再由应用同步这一变更;Needless UI 日程表只报告变更,你更新 events 后变更才会保留,因此你的数据始终是唯一的数据源。另外,allow 就是普通代码,无论变更来自指针还是键盘,每次变更前都会询问它,所以这条规则可以由你自己测试。会议室预订日历指南会一步步构建这个应用。
转换数据
| FullCalendar | Needless UI |
|---|---|
全天日程的 end 是日程结束后的那一天 | 全天日程的 end 是它的最后一天:需要减去一天 |
时间可能以 Z 或偏移量(例如 +02:00)结尾 | 不带偏移量的本地时间,例如 2026-11-02T09:30 |
星期用 0(星期日)到 6 表示,用于 businessHours 和 firstDay | 星期用 1(星期一)到 7(星期日)表示 |
时长用字符串表示,例如 '00:30' | 用数字表示:分钟数或小时数 |
| 资源先按 id 排序,再按标题排序 | 资源按数组中的顺序排列 |
对象形式的 rrule,以及 exrule | RFC 5545 字符串(例如 FREQ=WEEKLY;BYDAY=MO,FR),以及 exdate |
时区,例如 America/New_York | 先换算时间。nuiSchedulerFromIcs(text, { timeZone }) 会在读取 .ics 文件时完成换算。 |
如果需要尚未支持的功能
如果你的应用依赖时区、资源分组、外部拖放或打印,这个日程表目前还无法取代 FullCalendar。欢迎就你需要的功能提交 issue。至于其他内容,日程表页面列出了每个输入属性、输出属性和示例。