日历
逻辑预设
如果我们想要搭建这样一个日历组件,我们首先要解决三个问题:
- 如何解决不同月份的翻页问题,怎样保证翻页流畅?
- 日历每个单元渲染具体数据的算法?
- 日历单元的特殊样式渲染?
如何获取日历需要渲染的月份跨度?
根据开始日期和结束日期判断需要渲染的内容是否跨年 如果日期年份没变,则跨越了 x 个 tab 否则跨越了-x+12 个 tab
// 获取开始年、月数,当前年、月数,及其间的月数跨度 startDate/nowDate:"YYYY-MM-DD"
export const getMonthsRange = (props: {
startDate: string,
nowDate: string,
}) => {
const { startDate, nowDate } = props;
const startArr = startDate.split("-").map((item) => Number(item));
const nowArr = nowDate.split("-").map((item) => Number(item));
if (startArr[0] === nowArr[0]) {
return {
start: { year: startArr[0], month: startArr[1] },
now: { year: nowArr[0], month: nowArr[1] },
range: nowArr[1] + 1 - startArr[1],
};
} else {
return {
start: { year: startArr[0], month: startArr[1] },
now: { year: nowArr[0], month: nowArr[1] },
range: 12 + 1 - startArr[1] + nowArr[1],
};
}
};
怎样保证翻页流畅?
对于翻页操作,我们可以手写滑动 tabs 或者依赖一些现成的库,因为手写滑动 tabs 的动画时间开销会比较大,所以我们最后选择使用一个现成的 tabs 库——rmc-tabs 我们会用到以下三个属性 初始页面 index,我们取月份跨度的最大值-1,也就是当前月的 index 需要渲染的 tabs 标题和 key,可以在 onChange 回调中拿到,一个小函数可以搞定(本需求年份跨度不超过两年,如果需要渲染更多年份这里需要改逻辑)
tabs={Array.from(new Array(months_range.range).keys()).map((item) => {
const month =
(months_range.start.month + item) % 12 === 0
? 12
: (months_range.start.month + item) % 12; // 边界情况:%12===0会转成0
const year =
months_range.start.month + item > 12
// 跨年了,肯定用上nowYear
? months_range.now.year
// 没跨年,直接用startYear就行
: months_range.start.year;
return {
key: `${year}-${month > 9 ? month : `0${month}`}`,
title: `${month}月`,
};
})}
//months_range.range is a number 24
效果如下
tabs={[{key:2024-01,title:'01月'}],......}