SepCalendar 日历组件 v1.0.0
月 / 年 / 十年 / 议程 四视图 · 单选 / 范围 / 多选 · 边界限制 / 只读 · 跨日事件条 / 异步加载 · 数据导入导出
1. 基础月视图
JS API 初始化
选中:无
2. 周起始日 / 显示其他月份
JS API 初始化
3. 显示周数(ISO)
JS API 初始化
4. 范围选择
JS API 初始化
范围:无
5. 禁用日期(周末)
JS API 初始化
6. 自定义单元格(日程标记)
JS API 初始化
7. 全屏模式
JS API 初始化
8. 年视图 / 十年视图(点击标题切换)
JS API 初始化
9. 实例方法
JS API 初始化
10. 订阅与状态
JS API 初始化
状态变化:等待中…
12. 事件日程条
单元格内彩色事件条(按优先级排序,仅显示最高优先级,其余在 Popover 查看)+ 点击回调
13. 议程视图
panelMode: 'agenda' 按月事件列表,今天标记
14. 面板滑动动画
prev/next 带动画切换月份
15. 日期详情 Popover
hover 事件日 200ms 弹出详情浮层,可点击事件行
16. 日历密度
compact / normal / comfortable 三档视觉密度
compact
normal
comfortable
17. 日历尺寸
small / default / large 三种整体尺寸
small
default
large
18. 农历 / 节气 / 节假日
复用 DatePicker 的农历与节假日工具,显示于日期数字下方
农历
农历 + 节气 + 节假日
19. 日期边界限制 minDate / maxDate
超出范围的日期禁用,导航按钮自动拦截边界
20. 只读模式 readonly
readonly=true 时不可点击选择,仅展示
21. 多日期选择 multiple
点击切换选中/取消,getValue 返回 Date[]
已选:无
22. 跨日事件条(多日事件)
事件配置 start/end 字段,跨多日渲染为连续色带
23. 事件异步加载 eventSource
切换月份时按需拉取事件,加载中显示 loading 遮罩
24. 数据导入导出
节假日 / 纪念日 / 事件 支持 JSON & CSV 导入导出,可从本地文件导入
操作结果:无
详细说明
SepCalendar 零依赖原生日历面板组件,支持月/年/十年/议程四视图切换、单选/范围/多选三种选择模式、minDate/maxDate 日期边界、readonly 只读模式、自定义单元格渲染、日程标记点、键盘导航、单日/跨日事件日程条、eventSource 异步加载、Hover Popover、日历密度切换、节假日/纪念日/事件的 JSON & CSV 导入导出。基于 SepBase 组件工厂,遵循 a/b/c/d 四层拆分架构。
Props 配置项
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value | Date | string | null | null | 初始选中日期 |
| panelDate | Date | string | new Date() | 初始面板日期 |
| panelMode | string | 'month' | 初始视图:month / year / decade / agenda |
| firstDayOfWeek | number | 0 | 周起始日:0=周日,1=周一 |
| fullscreen | boolean | false | 全屏模式,撑满容器 |
| showWeekNumbers | boolean | false | 显示 ISO 周数 |
| showOtherMonths | boolean | true | 显示非当前月份的日期 |
| fixedWeekCount | boolean | false | 固定显示 6 周 |
| selectionMode | string | 'single' | 选择模式:single / range / multiple |
| range | Date[] | null | 初始日期范围 [start, end] |
| multipleDates | Date[] | [] | 多选模式初始选中日期数组 |
| minDate | Date | string | null | 最小可选日期,超出禁用 |
| maxDate | Date | string | null | 最大可选日期,超出禁用 |
| readonly | boolean | false | 只读模式,不可点击选择 |
| disabledDate | (date) => boolean | null | 禁用日期判定函数 |
| dateRender | (date) => string | null | null | 自定义单元格文本 |
| dateMark | (date) => { colors } | null | null | 自定义标记点 |
| events | { date\|start, title, end?, color?, time?, id?, priority? }[] | [] | 事件日程列表。支持单日(date)和跨日(start/end)两种 |
| maxVisibleEvents | number | 1 | 每格最多显示事件条数(按 priority 降序取前 N 条,其余在 Popover 查看) |
| showEventPopover | boolean | true | hover 事件日是否弹出详情浮层 |
| eventSource | (start, end) => Promise | null | 事件异步数据源,切换月份时按需加载 |
| showLunar | boolean | false | 显示农历日期(复用 SepLunarUtils) |
| showSolarTerm | boolean | false | 显示二十四节气 |
| showHoliday | boolean | false | 显示公历/农历节日及法定节假日(含休/班角标) |
| showAnniversary | boolean | false | 显示纪念日(如万圣节、圣诞节等,无节日时显示) |
| anniversaryData | Object | null | 自定义纪念日数据,格式同 DatePicker |
| holidayData | object | null | 自定义法定节假日数据 `{ "MM-DD": { name, isOffDay } }`,未传时自动从 API 加载 |
| density | string | 'normal' | 密度:compact / normal / comfortable |
| size | string | 'default' | 整体尺寸:small / default / large |
| onSelect | (date, info) => void | null | 选中回调 |
| onPanelChange | (date, mode) => void | null | 面板变化回调 |
| onRangeChange | (range) => void | null | 范围变化回调 |
Methods 方法
| 方法 | 参数 | 返回 | 说明 |
|---|---|---|---|
| getValue() | - | Date | null | 获取当前选中日期 |
| setValue(date) | Date | string | null | void | 设置选中日期 |
| getRange() | - | [Date, Date] | null | 获取日期范围 |
| setRange([s, e]) | Date[] | void | 设置范围(自动排序) |
| getMultipleDates() | - | Date[] | 获取多选模式选中日期数组 |
| setMultipleDates(dates) | Date[] | void | 设置多选模式选中日期 |
| getPanelDate() | - | Date | 获取当前面板日期 |
| setPanelDate(date) | Date | string | void | 设置面板日期(切换月份) |
| getPanelMode() | - | string | 获取视图:month / year / decade / agenda |
| setPanelMode(mode) | string | void | 切换视图模式 |
| getEvents() | - | object[] | 获取当前事件列表 |
| setEvents(events) | object[] | void | 设置事件列表(重新渲染) |
| setMaxVisibleEvents(n) | number | void | 设置每格最多事件条数 |
| setShowEventPopover(v) | boolean | void | 开关 Popover 详情浮层 |
| setEventSource(fn) | function | void | 设置事件异步数据源,立即触发当前月份加载 |
| setMinDate(date) | Date | string | null | void | 设置最小可选日期 |
| setMaxDate(date) | Date | string | null | void | 设置最大可选日期 |
| setReadonly(v) | boolean | void | 切换只读模式 |
| exportHolidayData(format) | 'json' | 'csv' | string | 导出节假日数据 |
| importHolidayData(input, options) | string | object, {merge?} | boolean | 导入节假日数据 |
| exportAnniversaryData(format) | 'json' | 'csv' | string | 导出纪念日数据 |
| importAnniversaryData(input, options) | string | object, {merge?} | boolean | 导入纪念日数据 |
| exportEvents(format) | 'json' | 'csv' | string | 导出事件数据 |
| importEvents(input, options) | string | array, {merge?} | boolean | 导入事件数据 |
| download(name, content, mime) | string, string, string | void | 触发浏览器下载文件 |
| clearImportedHolidayData() | - | number | 清空导入的节假日数据(保留系统默认) |
| clearImportedAnniversaryData() | - | number | 清空导入的纪念日数据(保留系统默认) |
| clearImportedEvents() | - | number | 清空导入的事件数据(保留系统默认) |
| setDensity(v) | string | void | 设置密度:compact / normal / comfortable |
| prev() | - | void | 切换到上一月 |
| next() | - | void | 切换到下一月 |
| prevYear() | - | void | 切换到上一年 |
| nextYear() | - | void | 切换到下一年 |
| today() | - | void | 切换到本月 |
| subscribe(fn) | (state) => void | unsubscribe | 订阅状态变化 |
| destroy() | - | void | 销毁实例 |
Events 事件
| 事件 | 回调参数 | 说明 |
|---|---|---|
| onSelect | (date, info) | single/range 选中时触发;multiple 模式返回 (dates[]) |
| onPanelChange | (date, mode) | 面板切换(上月/下月/年/十年)时触发 |
| onRangeChange | (range) | 范围选择完成时触发 |
| onEventClick | (event) | 事件条 / 议程行 / Popover 行点击时触发 |
i18n 国际化
日历内置文本均通过 $.t() 获取,支持中英文切换。已注册的语言包 key:
| Key | zh-CN | en-US | 用途 |
|---|---|---|---|
| calendar.today | 今天 | Today | today 按钮文本 |
| calendar.noEvents | 本月暂无日程安排 | No events this month | 空状态提示 |
| calendar.offDay / workDay | 休 / 班 | Off / Work | 节假日角标 |
| calendar.restDay / workdayLabel | 休息日 / 工作日 | Rest day / Workday | 角标 tooltip |
| calendar.eventsCount | {count} 个事件 | {count} events | 事件计数 tooltip |
| calendar.agenda | 日程 | Agenda | 议程视图标题 |
| calendar.week | 周 | (空) | 星期前缀 |
| calendar.months | 1月~12月 | Jan~Dec | 年视图月份名 |
| datePicker.today | 今天 | Today | today 按钮/标签 |
| datePicker.prevMonth/nextMonth | 上/下个月 | Prev/Next Month | 导航按钮 title |
| datePicker.prevYear/nextYear | 上/下一年 | Prev/Next Year | 年导航按钮 title |
| datePicker.month/year/day | 月/年/日 | (空) | 日期格式片段 |
| datePicker.weekdays.{0-6} | 日~六 | Su~Sa | 星期表头 |
开发路线图
| 阶段 | 功能 | 状态 |
|---|---|---|
| P0-1 | minDate / maxDate 日期边界限制 + readonly 只读模式 | ✅ 完成 |
| P0-2 | multiple 多日期选择模式 | ✅ 完成 |
| P0-3 | 跨日事件(多日事件条)start / end | ✅ 完成 |
| P0-4 | 事件异步加载 eventSource(防竞态 + 缓存) | ✅ 完成 |
| P0-5 | 数据导入导出:节假日 / 纪念日 / 事件 JSON & CSV | ✅ 完成 |
| P0-6 | 导入数据可清空(区分系统默认与导入数据) | ✅ 完成 |
| P0-7 | i18n 国际化(中/英) | ✅ 完成 |
| P0-8 | 通用文件导入工具 SepBase._pickAndReadText | ✅ 完成 |
| P0-9 | Popover 默认上方弹出 | ✅ 完成 |
| P1-1 | 周视图 / 日视图(时间轴) | 📋 待开发 |
| P1-2 | 拖拽创建 / 调整事件 | 📋 待开发 |
| P1-3 | 事件重复规则(RRULE) | 📋 待开发 |
| P1-4 | iCal 格式导入导出 | 📋 待开发 |
| P1-5 | 移动端手势(swipe 切换月) | 📋 待开发 |
架构
基于 SepBase 组件工厂,遵循 a/b/c/d 四层拆分架构:
| 层 | 文件 | 职责 |
|---|---|---|
| a 工具层 | 50a-calendar-utils.js | 纯函数无状态:日期计算、事件查询、CSV 解析 |
| b 构建层 | 50b-calendar-dom.js | DOM 骨架创建:根元素 + 头部/星期表头/主体容器 |
| c 引擎层 | 50c-calendar.js | 状态管理、渲染逻辑、事件处理、动画调度 |
| d 工厂层 | 50d-calendar.js | 对外 API、配置初始化、Setter/方法注册 |