- 前端
- UI组件
- 小程序
- 设计系统
- 移动开发
【免费下载链接】tdesign-miniprogram
Wechat MiniProgram and Uniapp UI components lib for TDesign
导读
Calendar是 TDesign 小程序组件库(tdesign-miniprogram)中用于"按照日历形式展示数据或日期的容器"的组件,支持单选、多选、区间选择三种模式,并提供翻页切换、自定义格式化、国际化等能力。本文将基于官方文档(packages/components/calendar/README.en-US.md),结合组件源码与测试用例,完整讲解组件的引入方式、全部 Props / Events / Slots / CSS Variables 的配置含义,并给出可直接运行的代码示例,帮助你在微信小程序中快速落地日期选择功能。
说明:Calendar 组件自
0.22.0版本上线,渲染框架支持情况为 WebView。以下所有版本号标记(如1.11.2、0.34.0)均取自官方文档,表示该能力引入的版本。
一、组件引入:全局与局部两种方式
Calendar 组件与其他 TDesign 组件一样,可通过全局或局部方式注册:
- 全局引入:在 miniprogram 根目录下的
app.json中配置usingComponents; - 局部引入:在需要使用日历的页面或组件的
index.json中配置。
"usingComponents": { "t-calendar": "tdesign-miniprogram/calendar/calendar" }组件内部依赖t-popup、t-button、t-icon三个子组件,在 calendar.json 中已声明(styleIsolation: apply-shared)。引入后即可在 WXML 中直接使用<t-calendar>。
从源码结构看,Calendar 组件由以下文件组成,便于后续深度阅读:
- 组件逻辑:calendar.ts
- 属性声明:props.ts
- 类型定义:type.ts
- 模板:calendar.wxml、template.wxml、calendar-header.wxml
- 样式:calendar.less
- 底层算法:common/shared/calendar/index.ts
二、Calendar Props:完整配置参数解析
下表完整列出组件所有属性(与官方文档一致),并在其后补充源码层面的实现说明。
| name | type | default | description | required | | -- | -- | -- | -- | -- | | style | Object | - | 样式 | N | | custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N | | allow-same-day | Boolean | false |1.11.2。是否允许区间选择日历的起止时间相同,仅当type='range'时有效 | N | | auto-close | Boolean | true |0.34.0。自动关闭;在点击关闭按钮、确认按钮、遮罩层时自动关闭,不需要手动设置 visible | N | | confirm-btn | String / Object | '' | 确认按钮。值为 null 则不显示确认按钮;值为字符串则自定义按钮文本;值为 Object 则透传 Button 组件属性 | N | | first-day-of-week | Number | 0 | 第一天从星期几开始,默认 0 = 周日 | N | | format | Function | - | 用于格式化日期的函数 | N | | locale-text | Object | - | 国际化文案 | N | | max-date | Number | - | 最大可选的日期,不传则默认半年后 | N | | min-date | Number | - | 最小可选的日期,不传则默认今天 | N | | readonly | Boolean | - |1.9.7。是否只读,只读状态下不能选择日期 | N | | switch-mode | String | none |1.8.2。切换模式:none 平铺所有月份;month 按月切换;year-month 既按年也按月切换 | N | | title | String | - | 标题,不传默认为"请选择日期" | N | | type | String | single | 选择类型:single 单选;multiple 多选;range 区间选择 | N | | use-popup | Boolean | true |0.32.0。是否使用弹出层包裹日历 | N | | using-custom-navbar | Boolean | false | 是否使用了自定义导航栏 | N | | value | Number / Array | - | 当前选择的日期,不传则选用 minDate 或今天,优先级 minDate > today;type 为 multiple 或 range 时传数组 | N | | default-value | Number / Array | undefined | 同上,非受控属性 | N | | visible | Boolean | false | 是否显示日历;usePopup 为 true 时有效 | N |
2.1 选择类型 type:single / multiple / range
type控制日历的核心行为,对应 type.ts 中TdCalendarProps.type的类型'single' | 'multiple' | 'range',默认single。三种模式的差异在底层算法类 common/shared/calendar/index.ts 的select与calcType中体现:
- single:点击即选中,
value为单个时间戳; - multiple:点击切换选中/取消,
value为时间戳数组(源码中用isSameDate判断是否已选中,已选中则从数组移除,否则追加); - range:第一次点击作为起点,第二次点击作为终点,
value为[start, end]数组;若点击日期早于起点则重新以该日期为起点。当起止日期相同且allowSameDay为 false 时,区间会被重置为仅含起点。
区间模式下的日期状态由calcType计算得出:起点为start、终点为end、中间日期为centre,起止相同且allowSameDay时为start-end。
2.2 翻页切换 switch-mode:none / month / year-month
switch-mode用于控制月份/年份的切换方式(1.8.2引入):
none(默认):平铺展示minDate到maxDate之间的所有月份,滚动查看;month:一次展示一个月,头部提供前后月份切换按钮;year-month:在month基础上增加前后年份切换按钮。
从 calendar-header.wxml 可以看到,year-month模式会渲染chevron-left-double/chevron-right-double(按年切换)与chevron-left/chevron-right(按月切换)图标,且切换按钮的禁用状态由 calendar.ts 中updateActionButton依据minDate/maxDate计算。切换行为定义在handleSwitchModeChange,其底层月份/年份偏移逻辑见 utils.ts(getPrevMonth/getNextMonth/getPrevYear/getNextYear)。
2.3 日期范围 min-date / max-date 与默认值规则
minDate:最小可选日期,不传默认今天(底层 common/shared/date.ts 的getDate());maxDate:最大可选日期,不传默认半年后(getDate(6),即当前日期 + 6 个月);value不传时,初始值优先取minDate,否则取今天 0 点的时间戳;range模式会将终点初始化为起点次日(见 calendar.tsinitialValue)。
超出范围、早于minDate或晚于maxDate的日期会被标记为disabled(不可点击)。
2.4 确认按钮 confirm-btn 的三种形态
confirm-btn支持字符串 / 对象 /null三种取值(默认''):
- 值为
null:不显示确认按钮,此时type='single'或区间已选满(rawValue.length === 2)时,选择完即自动关闭并触发change事件; - 值为字符串:自定义按钮文本,如
confirm-btn="好的"; - 值为对象:透传 Button 组件属性,例如
{ content: 'ok', theme: 'danger' }。
测试用例test/index.test.js 中的:custom button用例验证了confirmBtn: { content: 'ok' }时按钮文本为ok;:without-button用例验证了confirm-btn="{{null}}"时点击日期立即返回结果。在组件内部,confirmBtn的 observer 会将字符串转为{ content }对象,将'slot'特殊值交给插槽渲染(见 calendar.ts 的confirmBtnobserver)。
2.5 格式化函数 format:为日期附加文字
format是形如(day: TDate) => TDate的函数(CalendarFormatType,定义见 type.ts),其中:
type TDateType = 'selected' | 'disabled' | 'start' | 'start-end' | 'centre' | 'end' | ''; interface TDate { date: Date; day: number; type: TDateType; className?: string; prefix?: string; suffix?: string; }它会在每个日期格子渲染前被调用,返回值可修改prefix(格子上方文字)、suffix(格子下方文字)与className。模板 template.wxml 中,prefix与suffix分别渲染在日期上下方,suffix的状态色(选中/起点/终点为反色,禁用为弱色)在 calendar.less 中定义。
官方示例 custom-text/index.js 展示了两种典型用法:
singleFormat(day) { day.suffix = '¥60'; return day; }, format(day) { const { date } = day; const year = date.getFullYear(); const month = date.getMonth() + 1; const curDate = date.getDate(); day.suffix = '¥60'; if (year === 2022) { if (month === 2) { const map = { 1: '初一', 2: '初二', 3: '初三', 14: '情人节', 15: '元宵节' }; if (curDate in map) { day.prefix = map[curDate]; // 格子上方文字 day.suffix = '¥100'; // 格子下方文字 day.className = 'is-holiday'; // 附加样式类 } } } return day; },2.6 国际化 locale-text
localeText的 TS 类型为CalendarLocaleText:
interface CalendarLocaleText { title?: string; // 标题文案 weekdays?: string[]; // 星期表头(长度为 7 的数组) monthTitle?: string; // 月份标题模板,支持 {year} / {month} 占位符 months?: string[]; // 12 个月的名称数组 confirm?: string; // 确认按钮文案 }组件内置中文语言包(locale/zh_CN.ts):title: '请选择日期'、weekdays: ['日','一',...]、monthTitle: '{year} 年 {month}'、months: ['1 月', ...]、confirm: '确认'。月份标题中的{year}/{month}占位符由 calendar.wxs 的getMonthTitle完成替换(月份自动补零)。
官方国际化示例 local-text/index.js 配置了英文文案:
localeText: { title: 'Select Date', weekdays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], monthTitle: '{month} {year}', confirm: 'Confirm', months: ['January', 'February', /* ... */ 'December'], },组件通过 using-config.ts 的usingConfigBehavior 订阅全局语言包;当通过config-provider修改全局locale时,组件会自动刷新文案。localeText与全局配置的合并逻辑由 config-provider/use-config.ts 处理,localeText的优先级更高。
2.7 弹层与可见性:use-popup / visible / auto-close
usePopup(默认true):为 true 时日历由底部弹层t-popup(placement="bottom")包裹,模板见 calendar.wxml;为 false 时日历直接平铺在页面中,官方示例 without-popup/index.wxml 即展示内嵌用法;visible:控制弹层显隐,仅在usePopup为 true 时有效,默认 false;autoClose(默认true):点击关闭按钮、确认按钮、遮罩层时自动关闭弹层。组件 calendar.ts 的close(trigger)方法会在autoClose为 true 时主动将visible置为 false,并触发close事件;usingCustomNavbar:页面使用自定义导航栏时置为 true,弹层会避开自定义导航栏区域。
三、Calendar Events:事件体系与触发时机
| name | params | description | | -- | -- | -- | | change |(value: timestamp)|0.28.0。不显示 confirm-btn 时,完成选择时触发(暂不支持 type = multiple) | | close |(trigger: CalendarTrigger)|0.34.0。关闭时触发,trigger取值见下方类型定义 | | confirm |(value: timestamp)| 点击确认按钮时触发 | | panel-change |(detail: { year, month })|1.8.4。切换月或年时触发(switch-mode 不为 none 时有效) | | scroll |({scrollLeft, scrollTop, scrollHeight, scrollWidth, deltaX, deltaY})|1.4.6。滚动时触发 | | select |(value: timestamp)|0.28.0。点击日期时触发 |
close事件的CalendarTrigger类型为:
type CalendarTrigger = 'close-btn' | 'confirm-btn' | 'overlay' | 'auto-close';对应四种关闭来源:点击关闭按钮、点击确认按钮、点击遮罩层、自动关闭。
从源码看事件触发链路:
select:handleSelect中点击有效日期后触发,若readonly或日期为disabled则直接返回(见 calendar.tshandleSelect);confirm:onTplButtonTap中读取当前值后触发,同时关闭弹层(close('confirm-btn'));change:在不显示确认按钮(confirmBtn == null)且单选或区间已选满时,选择完成即触发并关闭弹层;注意文档说明change暂不支持 type = multiple;panel-change:handleSwitchModeChange在切换月份/年份时触发,回调参数month为 1 起始(源码中month + 1);scroll:由scroll-view的bindscroll直接转发事件详情。
value是受控属性(controlledProps将value绑定到confirm与change事件),同时提供非受控的defaultValue属性,二者用法与文档中value的默认值规则一致。
测试用例test/index.test.js 验证了关键行为:点击 disabled 日期不改变 value、点击普通日期不立即触发 confirm(需点击确认按钮)、关闭按钮触发close等。
四、Calendar Slots:自定义插槽
| name | Description | | -- | -- | | confirm-btn | 确认按钮 | | title | 标题 |
title插槽:替换日历顶部标题,配合title属性使用;不传插槽时展示title属性或语言包文案;confirm-btn插槽:完全自定义确认按钮区域。使用插槽前需将confirm-btn设置为字符串'slot',组件内部 calendar.ts 的confirmBtnobserver 会将'slot'值识别为插槽渲染模式;插槽内容仅在usePopup为 true 时渲染(见 template.wxml)。
五、CSS Variables:主题定制
组件提供以下 CSS 变量用于自定义样式(默认值取自 TDesign 设计令牌):
| Name | Default Value | Description | | -- | -- | -- | | --td-calendar-active-color | @brand-color | 选中态背景色 | | --td-calendar-bg-color | @bg-color-container | 日历背景色 | | --td-calendar-days-color | @text-color-secondary | 星期表头文字色 | | --td-calendar-item-centre-color | @brand-color-light | 区间中间日期背景色 | | --td-calendar-item-disabled-color | @text-color-disabled | 禁用日期文字色 | | --td-calendar-item-suffix-color | @text-color-placeholder | 日期下方文字色 | | --td-calendar-radius | @radius-extraLarge | 弹层圆角 | | --td-calendar-selected-border-radius | @radius-default | 选中格子圆角 | | --td-calendar-selected-color | @text-color-anti | 选中态文字色 | | --td-calendar-switch-mode-icon-color | @text-color-secondary | 翻页图标颜色 | | --td-calendar-switch-mode-icon-disabled-color | @text-color-disabled | 翻页图标禁用色 | | --td-calendar-title-color | @text-color-primary | 标题文字色 | | --td-calendar-title-font | @font-title-large | 标题字体 |
这些变量在 calendar.less 中逐一声明为 Less 变量并使用,例如:
@calendar-active-color: var(--td-calendar-active-color, @brand-color);因此在业务页面中,可通过page或组件外层作用域直接覆盖变量,例如:
page { --td-calendar-active-color: #00a870; --td-calendar-radius: 24rpx; }六、完整可运行示例:区间选择日历
综合以上知识点,一个完整的区间选择日历示例(对应官方示例 range/index.wxml 与 range/index.js)如下:
WXML:
<t-calendar visible="{{visible}}" value="{{value}}" minDate="{{minDate}}" maxDate="{{maxDate}}" type="range" bind:confirm="handleConfirm" /> <view class="wrapper" bind:tap="handleCalendar"> <view class="wrapper__left">{{_this.formatTimestamp(value[0])}}</view> <t-icon class="wrapper__center" name="swap-right" size="40rpx" /> <view class="wrapper__right">{{_this.formatTimestamp(value[1])}}</view> </view>JS:
Component({ data: { visible: false, value: [new Date(2024, 11, 5).getTime(), new Date(2024, 11, 10).getTime()], minDate: new Date(2024, 10, 1).getTime(), maxDate: new Date(2024, 12, 1).getTime(), }, methods: { handleCalendar() { this.setData({ visible: true }); }, handleConfirm(e) { this.setData({ value: e.detail.value }); }, }, });示例中时间戳格式化工具函数见 _example/calendar.wxs 的formatTimestamp,演示了如何在 WXML 层将时间戳转换为YYYY-MM-DD字符串(多选/区间场景以、拼接)。
七、底层原理:月份渲染与日期状态计算
Calendar 的日期算法被抽离为独立的纯类TCalendar(common/shared/calendar/index.ts),组件实例在created生命周期中初始化this.base = new TCalendar(this.properties),后续所有选择、月份计算均委托给该类:
getMonths():从minDate到maxDate逐月生成数据,每项包含year、month、months(该月每日的TDate数组,含type状态)与weekdayOfFirstDay(首日星期几,用于 WXML 中补齐前导空格);calcType():根据当前type与已选值判定每日状态(selected/disabled/start/centre/end/start-end),并调用format函数加工prefix/suffix/className;select():处理三种类型的选择逻辑(单选覆盖、多选增删、区间两点选法);getDays(weekdays):根据firstDayOfWeek重排星期表头顺序。
月份切换的边界控制由 calendar.ts 的updateActionButton完成:将目标月份与minDate/maxDate所在月份做时间戳比较,越界时置灰对应翻页按钮。switchMode为none时,全部月份一次性渲染进scroll-view并利用scrollIntoView定位到当前值所在月份;为month/year-month时仅渲染currentMonth单月面板。
快照测试位于test/snapshots,覆盖基础、多选、区间、翻页、国际化、自定义文案、自定义范围、不使用弹层等 8 个示例场景(见test/demo.test.js 的 mapper 列表),可作为理解组件渲染结果的参考。
八、常见使用要点小结
- 最小可用:
<t-calendar visible="{{visible}}" bind:confirm="onConfirm" />即可得到一个默认单选、弹层展示、自动关闭的日历; - 隐藏确认按钮:
confirm-btn="{{null}}",单选或区间选满后自动完成并触发change; - 嵌入页面:
use-popup="{{false}}"将日历平铺在页面,配合bind:select使用; - 只读:
readonly(1.9.7起)禁止点击选择; - 区间同日:
type="range"且需要允许起止同日时开启allow-same-day(1.11.2起); - 翻页联动:
switch-mode="year-month"并监听panel-change获取当前年月的回调; - 自定义文字:通过
format为每个日期追加prefix/suffix/className; - 多语言:全局走
config-provider切换locale,局部覆盖用locale-text。
如需进一步了解组件在全局配置、弹层、按钮、图标等基础设施上的实现,可继续阅读 config-provider、popup、button、icon 等目录下的对应文档与源码。
- 前端
- UI组件
- 小程序
- 设计系统
- 移动开发
【免费下载链接】tdesign-miniprogram
Wechat MiniProgram and Uniapp UI components lib for TDesign
相关推荐
TDesign Uniapp Calendar 日历组件全解析:API 配置、事件体系与源码实现原理
TDesign Uniapp Calendar 日历组件全解析:API 配置、事件体系与源码实现原理 本文以 TDesign 开源仓库中 packages/un
前端UI组件小程序设计系统移动开发终极指南:wx-calendar微信小程序日历组件从零到精通实战
终极指南:wx calendar微信小程序日历组件从零到精通实战 在日常的小程序开发中,你是否遇到过这样的场景:需要为用户展示一个可交互的日历界面,让用户能够轻
UI组件移动开发TDesign 小程序骨架屏 Skeleton 组件完全指南:从配置到源码实现
TDesign 小程序骨架屏 Skeleton 组件完全指南:从配置到源码实现 TDesign 小程序(tdesign miniprogram)的 Skelet
前端UI组件小程序设计系统移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考