小程序滚动日历组件
前段时间产品提出这个需求,要求做一个日历容器,并要求是滚动,不能是那种每个月切换的容器,所以我就在网上大概查找了一下类似组件,滚动的容器较少,于是我就自己写了这个组件,以下是大概的js思路,wxml和css就不附上了,每个UI都有不同的想法
- 在ready中初始化组件数据
/**
* @description: 初始化
*/
ready() {
// 这两个数据是从页面中传过来的,起始时间和结束时间
// 数组类型 [year, month, day]
const { endDate, startDate } = this.data
let monthList = [] // 这个用于wxml中遍历,以每月为item
// 未跨年
if ( endDate[0] === startDate[0]) {
let rangeMonth = endDate[1] - startDate[1]
for (let i = 0; i <= rangeMonth; i++) {
let date = [startDate[0], startDate[1] + i + 1]
// monthInitData()初始化每月数据
let days = this.monthInitData(startDate[0], startDate[1] + i)
monthList.push({
date,
days,
})
}
} else {
// 跨年前月份
for (let i = 0, lng = 12 - startDate[1]; i < lng; i++) {
let date = [startDate[0], startDate[1] + i + 1]
let days = this.monthInitData(startDate[0], startDate[1] + i)
monthList.push({
date,
days,
})
}
// 跨年后月份
for (let i = 0; i <= endDate[1]; i++) {
let date = [endDate[0], i + 1]
let days = this.monthInitData(endDate[0], i)
monthList.push({
date,
days,
})
}
}
this.setData({
monthList,
})
}
- 初始化每月数据:
逻辑是获取每个月第一天的星期数和每个月的最大天数,然后在之前和之后的空数据填充item占位
然后遍历,根据不同的需求,在遍历中处理,最后在html中flex布局即可
/**
* @description: 初始化每月数据
* @param: { number } year 年
* @param: { number } month 月
*/
monthInitData(year, month) {
let { calendarValue, startDate, endDate }= this.data, // 当前点击时间,起始时间,结束时间
firstWeek = new Date(year, month, 1).getDay(), // 本月的第一天的星期数
days = [], // 日期数组
max = this.getMonthMax(year, month + 1), // 每月最大天数
lastWeek = new Date(year, (month + 1), 0).getDay() // 本月的最后一天的星期数
// 填充每月一号之前的空数据
if (firstWeek > 0) {
for (let i = 0; i < firstWeek; i++) {
days.push({
day: 0
})
}
}
let currentTime = 0,
startTime = 0,
endTime = 0
if (calendarValue[0]) {
currentTime = new Date(calendarValue[0], calendarValue[1], calendarValue[2]).getTime()
}
if (startDate[0]) {
startTime = new Date(startDate[0], startDate[1], startDate[2]).getTime()
}
if (endDate[0]) {
endTime = new Date(endDate[0], endDate[1], endDate[2]).getTime()
}
for (let i = 1; i <= max; i++) {
// 以下状态是需要在html中判断处理,根据自己需求改变
let current = false, // 当前点击状态
disabled = false, // 禁止状态
now = false, // 今天显示文案
time = new Date(year, month, i).getTime(),
nowTime = [new Date().getFullYear(), new Date().getMonth(), new Date().getDate()]
if (currentTime && currentTime == time) current = true
if (startTime && startTime > time) disabled = true
if (endTime && endTime < time) disabled = true
if (year === nowTime[0] && month === nowTime[1] && i === nowTime[2]) now = true
days.push({
day: i,
current,
disabled,
now,
})
}
// 填充每月最后一天之后的空数据
if (lastWeek != 6) {
for (let i = 0, l = (6 - lastWeek); i < l; i++) {
days.push({
day: 0
})
}
}
return days
},
/**
* 获取一个月最大天数
* @method getMonthMax
* @param: { number } year 年份
* @param: { number } month 月份
*/
getMonthMax(year, month) {
let max = 31
if (month == 4 || month == 6 || month == 9 || month == 11) {
max = 30
} else if (month == 2) {
if (((year % 4) == 0 && (year % 100) > 0) || (year % 400) == 0) {
max = 29
} else {
max = 28
}
}
return max
},
- 以上就是核心逻辑,像一些弹窗事件和一些点击事件就不附上来了