amis Calendar 日历日程组件完全指南:从日程配置到事件动作的 JSON 实战

发布时间:2026/9/13 7:04:23
amis Calendar 日历日程组件完全指南:从日程配置到事件动作的 JSON 实战
amis Calendar 日历日程组件完全指南从日程配置到事件动作的 JSON 实战【免费下载链接】amis前端低代码框架通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amisamis 是前端低代码框架通过 JSON 配置即可生成各类页面而 Calendar日历日程组件是其内置的日历 日程复合组件既能像日期选择器一样展示月历又能在具体日期格子上挂载日程数据并通过点击日程、点击日期派发事件与其他组件联动。本文基于 Calendar 官方文档 展开结合仓库源码Calendar.tsx、InputDate.tsx、DaysView.tsx与测试用例calendar.test.tsx带你完整掌握如何用schedules配置静态或数据源日程、如何自定义日程颜色与点击展示、如何开启放大模式、如何定制今日高亮样式以及如何通过事件与动作实现组件间联动。基本用法一份 JSON 生成带日程的月历Calendar 组件类型为type: calendar其核心数据是value当前选中的时间与schedules日程列表。看官方文档中最基本的示例{ type: calendar, value: 1638288000, schedules: [ { startTime: 2021-12-11 05:14:00, endTime: 2021-12-11 06:14:00, content: 这是一个日程1 }, { startTime: 2021-12-21 05:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程2 } ] }value使用 Unix 时间戳秒1638288000对应 2021-12-01 00:00:00东八区即日历定位到 2021 年 12 月与下方日程所在月份一致schedules数组中的每一项是一个日程对象包含三个核心字段startTime日程开始时间endTime日程结束时间content日程内容可以是任意内容字符串或渲染节点className可选日程的颜色样式类。值得说明的是schedules的startTime/endTime字符串遵循 moment.js 的字符串解析规则既支持2021-12-11 05:14:00这种YYYY-MM-DD HH:mm:ss格式也支持其他 moment 可解析的写法。底层渲染从 Renderer 注册到日程着色Calendar 在仓库中的渲染入口非常轻量它直接继承了日期选择控件的能力。见 packages/amis/src/renderers/Calendar.tsxRenderer({ type: calendar }) export class CalendarRenderer extends DateControlRenderer { static defaultProps { ...DateControlRenderer.defaultProps, embed: true }; }通过Renderer({type: calendar})装饰器将calendar类型注册进 amis 渲染器体系因此 JSON 中写type: calendar即可命中它继承自DateControlRenderer日期选择控件并默认开启embed: true内联展示日历面板而非弹出式这也是它区别于表单内input-date的形态关键。而日程数据的具体解析、点击事件、值变更逻辑都在日期控件的基类 packages/amis/src/renderers/Form/InputDate.tsx 中完成。其中构造阶段对schedules做了字符串 → 数据的解析let schedulesData props.schedules; if (typeof schedulesData string) { const resolved resolveVariableAndFilter(schedulesData, data, | raw); if (Array.isArray(resolved)) { schedulesData resolved; } }这说明schedules既支持写死数组也支持写字符串变量表达式如${schedules}从当前数据域取值——这正是从数据源获取日程的实现基础。日程与日期的匹配规则日程并不直接在日历上铺满而是由DaysView在渲染每一天的格子时动态计算该日是否命中日程。见 packages/amis-ui/src/components/calendar/DaysView.tsx 中的renderDayconst currentDateBegin currentDate.startOf(day); const startTime moment(item.startTime).startOf(day); const endTime moment(item.endTime).startOf(day); if ( currentDateBegin.isSameOrAfter(startTime) currentDateBegin.isSameOrBefore(endTime) ) { schedule.push(item); }即把日程的起止时间与当前日期都统一归一到当天 00:00:00再做闭区间比较。这意味着只要日程区间覆盖到某一天该天的日历格子上就会展示日程标识跨天日程如2021-12-21 05:14:00到2021-12-22 05:14:00会同时命中 12 月 21 日与 12 月 22 日两天。命中日程后普通模式下该日期格子会渲染一个小圆点/图标并带上第一条日程的className作为颜色。同时构造一份scheduleData传给点击回调const scheduleData { scheduleData: schedule.map((item: any) ({ ...item, time: moment(item.startTime).format(YYYY-MM-DD HH:mm:ss) - moment(item.endTime).format(YYYY-MM-DD HH:mm:ss) })), currentDate };可以看到传给上层展示的数据中自动补充了time字段格式为开始时间 - 结束时间供后续自定义日程展示时直接使用。支持从数据源中获取日程日程不一定写死在组件内也可以放在 Page 的data数据域中通过变量引用注入。官方文档给出了完整示例{ type: page, data: { schedules: [ { startTime: 2021-12-11 05:14:00, endTime: 2021-12-11 06:14:00, content: 这是一个日程1 }, { startTime: 2021-12-21 05:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程2 } ] }, body: [ { type: calendar, value: 1638288000, schedules: ${schedules} } ] }要点data.schedules可以是接口返回的数据、表单联动结果或任何数据域中的数组组件侧schedules写成${schedules}字符串即可底层在构造时通过resolveVariableAndFilter(schedulesData, data, | raw)解析数据域变化时基类componentDidUpdate中通过anyChanged([schedules, data], prevProps, props)监听变化并重新解析schedules实现日程的动态刷新。这一点也说明日程数据与页面数据域保持响应式绑定非常适合对接真实业务接口。自定义颜色className 与 scheduleClassNames单条日程着色在日程对象上直接加className即可为对应日程指定颜色{ type: calendar, value: 1638288000, schedules: [ { startTime: 2021-12-11 05:14:00, endTime: 2021-12-11 06:14:00, content: 这是一个日程1, className: bg-success }, { startTime: 2021-12-21 05:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程2, className: bg-info } ] }className使用的是 amis 内置的语义背景色类如bg-success、bg-info、bg-warning、bg-danger、bg-secondary即背景色样式体系中定义的颜色工具类。普通模式下命中日程的日期格子上日程图标会取该日第一条日程的className作为底色见DaysView中cx(ScheduleCalendar-icon, schedule[0].className)。全局日程色板如果你希望日程自动轮流使用一组颜色可用scheduleClassNames指定色板属性名类型默认值scheduleClassNamesArraystring[bg-warning, bg-danger, bg-success, bg-info, bg-secondary]默认提供了 5 种背景色循环使用。在 packages/amis-ui/scss/components/_calendar.scss 中可以看到ScheduleCalendar相关样式类如.ScheduleCalendar-icon、.ScheduleCalendar-large-schedule-content负责日程圆点、放大模式日程条等的外观渲染颜色最终由你传入的bg-*工具类决定。自定义日程展示scheduleAction点击日程格子时默认会弹出一个对话框展示该日所有日程的时间 内容。你可以通过scheduleAction完全自定义这一交互例如官方文档用抽屉drawer展示日程表格{ type: calendar, value: 1638288000, schedules: [ { startTime: 2021-12-11 05:14:00, endTime: 2021-12-11 06:14:00, content: 这是一个日程1 }, { startTime: 2021-12-21 05:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程2 } ], scheduleAction: { actionType: drawer, drawer: { title: 日程, body: { type: table, columns: [ { name: time, label: 时间 }, { name: content, label: 内容 } ], data: ${scheduleData} } } } }关键机制scheduleAction本质上是一个标准的 amis Action 配置actionType可为drawer、dialog、ajax等点击日程时由onScheduleClick回调触发表格数据data写成${scheduleData}正是上文提到的每个日期命中日程后组件会把该日的日程数组每条附带格式化好的time字段和currentDate一起打包成scheduleData对象注入到 action 数据域中若不配置scheduleAction组件会使用默认实现——见 InputDate.tsx 中的onScheduleClick默认是一个标题为日程Schedule的 dialog内部同样是时间/内容两列的表格数据源为${scheduleData}并开启closeOnEsc。const defaultscheduleAction { actionType: dialog, dialog: { title: __(Schedule), actions: [], closeOnEsc: true, body: { type: table, columns: [ {name: time, label: __(Time)}, {name: content, label: __(Content)} ], data: ${scheduleData} } } };因此你完全可以替换为带详情页跳转、接口拉取、表单编辑等更复杂的动作日程展示的想象空间很大。该行为在测试 calendar.test.tsx 中有Renderer:calendar scheduleAction用例进行快照验证。放大模式largeMode把largeMode设为true日历切换为放大模式每个日期格子内直接平铺展示日程条而非普通模式下的小圆点适合做日视图/周视图式的排期管理。官方示例{ type: calendar, value: 1638288000, largeMode: true, schedules: [ { startTime: 2021-12-10 23:59:59, endTime: 2021-12-11 00:00:00, content: 这是一个日程1 }, { startTime: 2021-12-12 00:00:00, endTime: 2021-12-13 00:00:01, content: 这是一个日程2 }, { startTime: 2021-12-20 05:14:00, endTime: 2021-12-21 05:14:00, content: 这是一个日程3 }, { startTime: 2021-12-21 05:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程4 }, { startTime: 2021-12-22 02:14:00, endTime: 2021-12-23 05:14:00, content: 这是一个日程5 }, { startTime: 2021-12-22 02:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程6 }, { startTime: 2021-12-22 02:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程7 }, { startTime: 2021-12-25 12:00:00, endTime: 2021-12-25 15:00:00, content: 这是一个日程8 } ] }从源码DaysView.tsx 的renderDay可以梳理出放大模式的渲染算法便于理解其表现最多平铺 3 条遍历命中该日的日程超过 3 条即停止剩余数量显示在格子底部更多__(more)提示中当日开始的日程直接作为日程条渲染周日weekday() 0时对跨周开始的日程计算其跨周宽度Math.min(endTime.diff(currentDate, days) 1, 7)并用width: width 00%控制日程条占位宽度实现条形跨日效果非周日且非当日开始的日程渲染为透明占位格className: bg-transparent用于维持行对齐行内排序通过height字段对最多 3 行的日程做位置整理保证同一日期的多条日程分列展示日程条内容支持 HTML 过滤渲染env.filterHtml样式类为ScheduleCalendar-large-schedule-content点击后同样触发onScheduleClick即scheduleAction。该模式在测试中有独立的Renderer:calendar largeMode用例packages/amis/__tests__/renderers/calendar.test.tsx对应的快照文件为 calendar.test.tsx.snap。今日高亮样式自定义todayActiveStyle该属性自 2.1.1 及以上版本提供。todayActiveStyle用于定制今天所在格子的高亮样式。注意示例中value用了NOW()表达式amis 内置的取当前时间函数保证今天始终处于激活态{ type: calendar, value: NOW(), todayActiveStyle: { backgroundColor: #ef4444 !important, color: #f8f9fa, border: none, borderRadius: 15px }, schedules: [ { startTime: 2021-12-11 05:14:00, endTime: 2021-12-11 06:14:00, content: 这是一个日程1 }, { startTime: 2021-12-21 05:14:00, endTime: 2021-12-22 05:14:00, content: 这是一个日程2 } ] }从源码看todayActiveStyle的实现很巧妙在 DaysView.tsx 的renderDays中只有当该格子的 class 包含rdtToday时才会把todayActiveStyle作为内联样式挂到日期span上由于日历本身有主题样式普通内联样式可能被覆盖因此组件额外通过todayDomRef对包含!important的属性值做了处理把!important后缀解析出来再用node.style.setProperty(prop, value, important)以最高优先级写入if (typeof value string !!~value.indexOf(!important)) { node?.style?.setProperty?.( kebabCase(key), String(value).replace(/\!important/, ).trim(), important ); }这也解释了为什么官方示例中backgroundColor写了#ef4444 !important——只有加上!important才能稳定覆盖主题的今日高亮背景。todayActiveStyle是一个Recordstring, any即 React 的CSSProperties对象支持任意 CSS 属性。Calendar 属性表以下为官方文档给出的完整属性表属性名类型默认值说明typestringcalendar指定为 calendar 渲染器schedulesArray{startTime: string, endTime: string, content: any, className?: string} \| string-日历中展示日程可设置静态数据或从上下文中取数据startTime和endTime使用 moment.js 字符串解析格式className参考 amis 背景色工具类如bg-success、bg-info、bg-warning、bg-danger、bg-secondaryscheduleClassNamesArraystring[bg-warning, bg-danger, bg-success, bg-info, bg-secondary]日历中展示日程的颜色色板scheduleActionSchemaNode-自定义日程展示点击日程时的动作largeModebooleanfalse放大模式格子内平铺日程条todayActiveStyleRecordstring, any-今日激活时的自定义样式补充说明源码佐证schedules同时允许数组字面量与字符串变量两种形态字符串会被resolveVariableAndFilter解析为数组参见 InputDate.tsxscheduleAction的类型为SchemaObject本质是标准 Action Schema见 Calendar.tsxtodayActiveStyle的类型为{[propName: string]: any}CSSProperties 风格见 Calendar.tsx。事件表Calendar 会对外派发以下事件可通过onEvent监听并通过actions配置执行动作在actions中可用${事件参数名}获取事件数据2.3.2 及以下版本为${event.data.[事件参数名]}。完整的事件动作机制请参考事件动作。事件名称事件参数说明changevalue: string组件的值时间值变化时触发clickvalue: string组件的值点击日期时触发mouseentervalue: string组件的值鼠标移入日期时触发mouseleavevalue: string组件的值鼠标移出日期时触发从源码可以确认这些事件都是值事件dispatchEvent通过resolveEventData(this.props, {value})派发其中value为当前选中日期按valueFormat || format默认X即 Unix 时间戳格式化后的字符串参见 InputDate.tsx。典型用法示例{ type: calendar, value: NOW(), onEvent: { click: { actions: [ { actionType: toast, args: { msg: 你点击了 ${value} } } ] } } }动作表Calendar 对外暴露以下特性动作其他组件可通过指定actionType: 动作名称、componentId: 该组件id来触发并用args: {动作配置项名称: xxx}配置参数。详细说明见事件动作——触发其他组件的动作。动作名称动作配置说明clear-清空reset-将值重置为初始值6.3.0 及以下版本为resetValuesetValuevalue: string更新的值更新数据对应的实现位于 InputDate.tsx 的doActionclear调用底层日期组件的clear()reset则从表单/Store 的 pristine 值初始值或resetValue中取回原值并调用reset()。例如通过按钮触发{ type: button, label: 清空日历, onClick: { actions: [ { actionType: clear, componentId: my_calendar } ] } }小结Calendar 组件把月历展示与日程管理合二为一schedules负责数据静态数组或数据域变量均可className/scheduleClassNames负责着色scheduleAction负责点击日程后的任意自定义交互largeMode提供适合排期的条状视图todayActiveStyle精确定制今日样式再叠加change/click/mouseenter/mouseleave事件与clear/reset/setValue动作Calendar 可以很好地承担考勤、排班、会议预订等场景的日历能力。想要查看更复杂的组合用法可以在仓库的 examples 目录与 日历测试用例 中继续探索。【免费下载链接】amis前端低代码框架通过 JSON 配置就能生成各种页面。项目地址: https://gitcode.com/GitHub_Trending/am/amis创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考