小程序滚动日历组件
前段时间产品提出这个需求,要求做一个日历容器,并要求是滚动,不能是那种每个月切换的容器,所以我就在网上大概查找了一下类似组件,滚动的容器较少,于是我就自己写了这个组件,以下是大概的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 },
- 以上就是核心逻辑,像一些弹窗事件和一些点击事件就不附上来了