Calendar
Mini-program developers can use the Calendar component to allow users to view and interact with dates based on the calendar form. This topic covers the user experience, attribute details, and sample code for the Calendar component.
User experience
The following images show a calendar with the default UI text and the localized version in English:
Default UI text | Localized version in English |
Attributes
Attribute | Data type | Default | Description |
defaultValue | N/A | The preselected date or date range when the calendar is first displayed. | |
value | N/A | The date or date range that is currently selected. | |
selectionMode | String |
| The type of date selection available to users. Valid values are:
|
monthRange | [Number,Number] | current month and next two months | The months displayed on the calendar. |
weekStartsOn | String |
| The first day of the week. Valid values are:
|
localeText | Partial<LocaleText> | See LocaleText for details. | The localized UI text for calendar display, such as the names for the months and the days of the week. Note: The default text is in Chinese. Specify this attribute to display text in another language. |
changedScrollIntoView | Boolean | N/A | Whether to scroll the view when the selected date is changed. |
onChange | (date: CalendarValue) => void | N/A | The callback function that is triggered when the selected date is changed. |
onFormatter | (cell: CellState, currentValue: CalendarValue) => CellState | N/A | The customized display and data for individual date cells. |
CalendarValue
CalendarValue represents the format of the selected dates on the calendar. It takes either of the following two forms:
- Number: A number that specifies a single day. The value is a timestamp that is accurate to the millisecond.
- [Number,Number]: An array of two numbers that specify the start and end dates of a continuous date range. Each number is a timestamp that is accurate to the millisecond.
CellState
CellState provides the state of date cells and is defined as:
interface CellState {
/**
* Whether the date cell is disabled.
*/
disabled: boolean;
/**
* The content that is displayed at the top of the date cell.
*/
top?: { label: string; className?: string };
/**
* The content that is displayed at the top of the date cell.
*/
bottom?: { label: string; className?: string };
/**
* The timestamp.
*/
time: number;
/**
* The date.
*/
date: number;
/**
* Whether the date cell is selected.
*/
isSelected: boolean;
}
LocaleText
LocaleText provides the localized UI text and is defined as:
interface LocaleText {
/**
* The names of the days of the week from Monday to Sunday.
* The default value is ['一', '二', '三', '四', '五', '六', '日'].
*/
weekdayNames: string[];
/**
* The names of the months. The default value is in 'YYYY年MM月' format.
*/
title: string;
/**
* Text for the current date on the cell. The default value is '今日'.
*/
today: string;
/**
* Text for the start date. The default value is '开始'.
*/
start: string;
/**
* Text for the end date. The dedault value is '结束'.
*/
end: string;
/**
* Text for same-day start and end. The default value is '开始/结束'.
*/
startAndEnd: string;
}
Sample code
The following sample code shows how to create different calendars. The Localize UI text section (line 71-78) in the AXML code, along with associated code samples, creates a calendar with English UI text, which corresponds to the localized visual example in User experience.
.axml
<ant-container
title="Default: Selection of a date range and display of 3 months beginning from the current month">
<view
slot="content"
style="height: 1000rpx">
<ant-calendar defaultValue="{{ demo1.defaultValue }}" />
</view>
</ant-container>
<ant-container
title="Selection of a single day">
<view
slot="content"
style="height: 1000rpx">
<ant-calendar
selectionMode="single"
defaultValue="{{ demo2.defaultValue }}" />
</view>
</ant-container>
<ant-container
title="Customize the top of the calendar">
<view slot="content">
<view class="custom-header">
<view
onTap="demo3PreviousMonth"
class="custom-header-left">
<ant-icon type="LeftOutline" />
Previous
</view>
<view>{{ demo3.title }}</view>
<view
onTap="demo3NextMonth"
class="custom-header-right">
Next
<ant-icon type="RightOutline" />
</view>
</view>
<ant-calendar monthRange="{{ demo3.monthRange }}">
<view slot="calendarTitle" />
</ant-calendar>
</view>
</ant-container>
<ant-container
title="Customize date cells">
<view slot="content">
<ant-calendar
monthRange="{{ demo8.monthRange }}"
onFormatter="{{ demo8Formatter ? demo8Formatter : 'demo8Formatter' }}" />
</view>
</ant-container>
<ant-container
title="Dynamic control, choose an end date within the following 3 days">
<view slot="content">
<ant-calendar
onFormatter="{{ demoFormatter ? demoFormatter : 'demoFormatter' }}" />
</view>
</ant-container>
<ant-container
title="Set Monday as the first day of the week">
<view
slot="content"
style="height: 1000rpx">
<ant-calendar weekStartsOn="Monday" />
</view>
</ant-container>
<ant-container
title="Localize UI text">
<view slot="content">
<ant-calendar
monthRange="{{ demo7.monthRange }}"
localeText="{{ demo7.localeText }}" />
</view>
</ant-container>
<ant-container
title="Control mode">
<view slot="content">
<ant-calendar
value="{{ demo9.value }}"
monthRange="{{ demo9.monthRange }}"
onChange="demo9HandleChange"
selectionMode="single" />
<ant-button
type="primary"
onTap="demo9HandlePreviousDay">
Previous
</ant-button>
<ant-button
style="margin-top: 8rpx"
type="primary"
onTap="demo9HandleNextDay">
Next
</ant-button>
</view>
</ant-container>
.js
import dayjs from 'dayjs';
const localeText = {
weekdayNames: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
title: 'YYYY/MM',
today: 'Today',
start: 'Start',
end: 'End',
startAndEnd: 'Start/End',
};
function demo8Formatter(cell) {
const isOdd = dayjs(cell.time).date() % 2 === 1;
const isNotBeginEnd = !cell.isSelectedBegin && !cell.isSelectedEnd;
const isWeekend = dayjs(cell.time).day() > 4;
let topClassName;
if (isNotBeginEnd) {
topClassName = isOdd ? 'odd' : 'even';
}
return {
top: {
className: topClassName,
label: isOdd ? 'Odd' : 'Even',
},
bottom: {
label: isWeekend ? 'Weekend' : '',
},
};
}
function demoFormatter(cell, value) {
if (Array.isArray(value) && value.length == 1) {
const current = value[0];
return {
disabled: dayjs(cell.time).diff(dayjs(current), 'days') > 3,
bottom: dayjs(cell.time).diff(dayjs(current), 'days') > 3
? {
label: 'Unselectable',
}
: undefined,
};
}
return {};
}
Page({
data: {
demo1: {
defaultValue: [Date.now(), Date.now()],
visible: true,
},
demo2: {
defaultValue: Date.now(),
visible: true,
},
demo3: {
title: dayjs(new Date().getTime()).format('YYYY年MM月'),
monthRange: [new Date().getTime(), new Date().getTime()],
visible: true,
},
demo7: {
localeText,
visible: true,
monthRange: [new Date().getTime(), new Date().getTime()],
},
demo8: {
visible: true,
monthRange: [new Date().getTime(), new Date().getTime()],
},
demo9: {
visible: true,
value: Date.now(),
monthRange: [new Date().getTime(), new Date().getTime()],
},
},
demo3NextMonth() {
const current = this.data.demo3.monthRange[0];
const newMonth = dayjs(current).add(1, 'month').toDate().getTime();
this.setData({
'demo3.title': dayjs(newMonth).format('YYYY年MM月'),
'demo3.monthRange': [newMonth, newMonth],
});
},
demo3PreviousMonth() {
const current = this.data.demo3.monthRange[0];
const newMonth = dayjs(current).add(-1, 'month').toDate().getTime();
this.setData({
'demo3.title': dayjs(newMonth).format('YYYY年MM月'),
'demo3.monthRange': [newMonth, newMonth],
});
},
demoFormatter,
demo8Formatter,
demo9HandleChange(value) {
this.setData({
'demo9.value': value,
});
},
demo9HandlePreviousDay() {
this.setData({
'demo9.value': this.data.demo9.value - 1000 * 24 * 3600,
});
},
demo9HandleNextDay() {
this.setData({
'demo9.value': this.data.demo9.value + 1000 * 24 * 3600,
});
},
});
.acss
page {
padding: 8px;
box-sizing: border-box;
}
.custom-header {
display: flex;
justify-content: space-between;
align-items: center;
height: 60rpx;
}
.custom-header-left {
display: flex;
align-items: center;
}
.custom-header-right {
display: flex;
align-items: center;
}
.odd {
color: red;
}
.even {
color: blue;
}
.json
{
"defaultTitle": "Calendar",
"usingComponents": {
"ant-icon": "antd-mini/es/Icon/index",
"ant-button": "antd-mini/es/Button/index",
"ant-calendar": "antd-mini/es/Calendar/index",
"ant-container": "antd-mini/es/Container/index"
}
}
FAQs
How do I set a default date range selection on the calendar?
To set a default date range, specify the start and end dates using defaultValue. For example, to set the start date to today and the end date to seven days later, use the following code:
defaultValue=[dayjs().startOf('date'), dayjs().add(7, 'days').startOf('date')];
How do I use onFormatter
to customize date cell data?
The onFormatter
function is used to customize the state and value of each date cell. For example, to make dates before today unselectable, take the following steps:
- Link to the method in the AXML file:
<calendar onFormatter="handleFormat" />
- Define the method in the JS file:
import dayjs from 'dayjs';
Page({
handleFormat(cell: CellState) {
// Make dates before today unselectable
return {
disabled: dayjs(cell.time).isBefore(dayjs().startOf('date')),
};
},
});