小程序日历代码实现逻辑
由于项目中使用到日历功能,考虑到后期维护及扩展的问题,自己手写了一个日历组件,解决目前项目中遇到的问题的同时,方便以后公司有需要用到的时候可以随时扩展和修改
日历样式
性能分析
目前只是在开发者工具上初步测试了一下,并未发现比较耗性能的代码,只是颜色搭配比较乱
逻辑分析
1、获取当前月份的天数,并得到本月的第一天是从周几开始的, 最后一天是从周几开始的
2、获取上月需要在本月展示的天数(即本月第一天是周几)
3、获取下月需要在本月展示的天数(即7-本月最后一天是周几)
总结:
从上面的逻辑中可以看到,很重要的一个点就是, 本月的第一天和本月的最后一天,从这个天数可以获取到本月前后两个月在本月展示的效果的
核心代码1-获取当月需要在页面上展示的天数
/**
* 加载当前月的天
*/
loadCurrentMonthDays(y, m) {
let currentDate = new Date(y, m, 0); //当前日期
let year = currentDate.getFullYear(); // 得到年份
let month = currentDate.getMonth() + 1; // 得到月份
let week = currentDate.getDay(); // 得到周几 (0: 周日 1: 周一 2: 周二 ...)
let day = currentDate.getDate(); // 今天几号
let daysLength = this.currentMonthDays(year, month); // 当前月份总共有多少天
month = month < 10 ? "0" + month : month
let nowDay = new Date();
let nowY = nowDay.getFullYear();
let nowM = nowDay.getMonth() + 1;
nowM = nowM < 10 ? "0" + nowM : nowM;
let nowD = nowDay.getDate();
let tempCurrentMonthDays = [];
for (let i = 1; i <= daysLength; i++) {
let date = i < 10 ? "0" + i : i;
let temp = {
year: year,
month: month,
day: date,
fullID: `${year}${month}${date}`,
isCurrentDay: `${nowY}${nowM}${nowD}` === `${year}${month}${date}` ? true : false, //是否是今天
isPointDay: this.data.selectDays.includes(`${year}${month}${date}`)
};
tempCurrentMonthDays.push(temp);
//初始化选中今天
if (temp.isCurrentDay && !this.data.activeDate) {
this.setData({
activeDate: temp
})
this.onChange(this.data.activeDate);
}
}
return tempCurrentMonthDays;
}
核心代码2-获取上月需要在页面上展示的天数
/**
* 获取上个月对应的日期
*/
loadLastMonthDays(y, m) {
let currentDate = new Date(y, m, 0); //当前日期
let year = currentDate.getFullYear(); // 得到年份
let month = currentDate.getMonth(); // 得到月份
let week = currentDate.getDay(); // 得到周几 (0: 周日 1: 周一 2: 周二 ...)
//获取本月第一天周几
let firstDate = new Date(`${year}/${month + 1}/01`);
week = firstDate.getDay(); // 得到周几 (0: 周日 1: 周一 2: 周二 ...)
let lastMonth = month;
let lastYear = year;
if (lastMonth == 0) {
lastYear = lastYear - 1;
lastMonth = 12;
}
//上月日期
let lastDate = new Date(year, month, 0);
let date = lastDate.getDate(); //上个月总共多少天
lastMonth = lastMonth < 10 ? "0" + lastMonth : lastMonth;
let tempMonthDays = [];
for (let i = date - week + 1; i <= date; i++) {
let date = i < 10 ? "0" + i : i;
tempMonthDays.push({
year: lastYear,
month: lastMonth,
day: date,
fullID: `${lastYear}${lastMonth}${date}`,
isPointDay: this.data.selectDays.includes(`${lastYear}${lastMonth}${date}`)
})
}
return tempMonthDays;
}
核心代码3-获取下月需要在页面上展示的天数
/**
* 获取下个月对应的日期
*/
loadNextMonthDays(y, m) {
let currentDate = new Date(y, m, 0); //当前日期
let year = currentDate.getFullYear(); // 得到年份
let month = currentDate.getMonth() + 1; // 得到月份
let date = currentDate.getDate(); // 获取本月天数
//获取本月最后一天周几
let endDate = new Date(`${year}/${month}/${date}`);
let week = endDate.getDay(); // 得到周几 (0: 周日 1: 周一 2: 周二 ...)
let nextMonth = month + 1;
let nextYear = year;
//下个月日期
if (nextMonth == 13) {
nextYear = nextYear + 1;
nextMonth = 1;
}
nextMonth = nextMonth < 10 ? "0" + nextMonth : nextMonth;
let tempMonthDays = [];
for (let i = 0; i < (7 - week - 1); i++) {
let date = i + 1;
date = date < 10 ? "0" + date : date;
tempMonthDays.push({
year: nextYear,
month: nextMonth,
day: date,
fullID: `${nextYear}${nextMonth}${date}`,
isPointDay: this.data.selectDays.includes(`${nextYear}${nextMonth}${date}`)
})
}
return tempMonthDays;
}
核心代码4-调用三个函数赋值
/**
* 加载当前月份日历
*/
loadCurrentMonth(type = "") {
let currentDate = (() => {
if (Object.keys(this.data.currentMonth).length === 0) {
return new Date();
}
return new Date(this.data.currentMonth.year, this.data.currentMonth.month, 0);
})(); //当前日期
let year = currentDate.getFullYear(); // 当前展示的年份
let month = currentDate.getMonth() + 1; // 当前展示的月份
if ("last" === type) {
month = month - 1;
if (month == 0) {
year = year - 1;
month = 12;
}
} else if ("next" === type) {
month = month + 1;
if (month == 13) {
year = year + 1;
month = 1;
}
}
month = month < 10 ? '0' + month : month;
this.setData({
currentMonth: { year, month }, // 当前展示的月份
lastMonthDay: this.loadLastMonthDays(year, month),
currentMonthDay: this.loadCurrentMonthDays(year, month),
nextMonthDay: this.loadNextMonthDays(year, month)
})
},
页面布局
在代码中定义了三个时间对象的数组,分别是上月天的对象数组,本月天的对象数组,下月天的对象数组,将这三个数组在页面上分别循环出来即达到上面图中展示的效果
注意
1、需要注意的点是在使用 new Date()的时候传入日期,需要使用 / 去分割,因为可能部分iPhone的机型不识别 - 的分割
2、可能有其他的实现日历的逻辑,此代码仅供参考