配景:近来接了个外包,此中有个打卡功能,里面包罗了一个日历,甲方要求百分百还原,闲暇之余就撸了一下,下面是效果图 源码地点 https://github.com/chenxuba/xx-calendar 求star ✨
分析:
- 要求左右箭头可切换上下月;
- 必要展示夏历日历;
- 点击日期拿到年月日(yyyy-mm-dd)
- 样式一比一还原
想法?:网上都没一毛一样的组件,那还想个der,自己撸一个啊~
组件我起名:xx-calendar
- 第一步:在小程序components目次下新建一个组件xx-calendar
- 第二步:在你想要引入的页面的xxx.json文件里引入该组件
{ "usingComponents": { "xx-calendar":"../../components/xx-calendar/xx-calendar" }}
<xx-calendar></xx-calendar>
- 第三步:前端写页面,啥都不要想,先撸样式,静态页面撸起走~
- 3.1 先撸头部
<!--components/xx-calendar/xx-calendar.wxml--><!-- 头部 --><view</blockquote>
- 选中状态和已打卡样式都临时是根据索引模拟出来的,夏历日期也不对
- 下面就来写js,获取上个月日期数组、当月日期数组和下个月日期数组
- 夏历临时先放一放
- 下面先来写三个方法,分别来 获取上个月日期、当月日期和下个月日期
- xx-calendar.js
- 点定义好本月的年月,渲染日历头部,而且把星期也换成变量,即:
data:{ year: new Date().getFullYear(), month: new Date().getMonth() + 1, weeksArr: ['日', '一', '二', '三', '四', '五', '六'],}
data:{ nowMonth: new Date().getMonth() + 1, //本月是几月 nowDay: new Date().getDate(), //本月当天的日期 lastMonthDays: [], //上一个月 nowMonthDays: [], //本月 nextMonthDays: [], //下一个月}
/** * 组件的方法列表 */ methods: { /** 获取上个月日期 */ getLastMonthDays(year,month){}, /** 获取当月日期 */ getNowMonthDays(year, month) {}, /** 获取下个月日期 */ getNextMonthDays(year, month) {}, }
- 为了方便调用,写一个总方法,一并调用这三个方法,并在ready里调用这个总方法,传入year和month,逻辑必要,还要写一个获取当月天数的方法
/** * 组件的方法列表 */ methods: { //获取当月天数 getThisMonthDays(year, month) { return new Date(year, month, 0).getDate(); }, /** 总方法 */ //创建日期 createDays(year, month) { this.getLastMonthDays(year, month) this.getNowMonthDays(year, month) this.getNextMonthDays(year, month) }, /** 获取上个月日期 */ getLastMonthDays(year, month) {}, /** 获取当月日期 */ getNowMonthDays(year, month) {}, /** 获取下个月日期 */ getNextMonthDays(year, month) {}, }, ready(){ let { year,month } = this.data this.createDays(year,month) }
/** 获取上个月日期 */ getLastMonthDays(year, month) { let nowMonthFirstDays = new Date(year, month - 1, 1).getDay() let lastMonthDays = [] if (nowMonthFirstDays) { //判定当月的第一天是不是星期天 //上个月体现多少天 let lastMonthNums = month - 1 < 0 ? this.getThisMonthDays(year - 1, 12) : this.getThisMonthDays(year, month - 1); //判定是否会跨年 //上个月从几号开始体现 for (let i = lastMonthNums - nowMonthFirstDays + 1; i <= lastMonthNums; i++) { let time = new Date(year, month - 2, i).toLocaleDateString() //对应的时间 lastMonthDays.push({ date: i, //几号 week: this.data.weeksArr[new Date(year, month - 2, i).getDay()], //星期几 time, isNowMonthDay: '' }); } } this.setData({ lastMonthDays }) console.log(lastMonthDays); },
- 打印效果可以看到 ,已经拿到上个月的日期已经对应的数据
- ⚠️:安卓手机上会存在bug,写法造成的,办理方法我放到文章末了
- 上个月的日期已经拿到了,下面可以在dom里渲染这个【lastMonthDays】数组了
getNowMonthDays(year, month) { let { nowMonth, nowDay } = this.data let nowMonthDays = [] let days = this.getThisMonthDays(year, month); //获取当月的天数 for (let i = 1; i <= days; i++) { let d = new Date(year, month - 1, i) let years = d.getFullYear() let months = d.getMonth() + 1 let day = d.getDate() let time = `${years+'/'+months +'/'+day}` // 2023/3/3 nowMonthDays.push({ date: i, //几号 week: this.data.weeksArr[new Date(year, month - 1, i).getDay()], //星期几 time, color: false, //为已打卡日期样式做准备 day, //反面会改成夏历 isNowMonthDay: (month == nowMonth && i == nowDay) ? "isNowMonthDay" : "" }); } this.setData({ nowMonthDays }) console.log(nowMonthDays); },
- 打印可以拿到当月的全部日期数组,重要圈出来的,默认选中当天的日期
- 日期数组拿到了,当天的选中状态条件也拿到了,下面微调下dom,渲染【nowMonthDays】和完满默认选中条件
/** 获取下个月日期 */ getNextMonthDays(year, month) { let { lastMonthDays, nowMonthDays, } = this.data let nextMonthDays = [] let nextMonthNums = (lastMonthDays.length + nowMonthDays.length) > 35 ? 42 - (lastMonthDays.length + nowMonthDays.length) : 35 - (lastMonthDays.length + nowMonthDays.length) //下个月体现多少天 let nowYear = (parseInt(month) + 1) > 12 ? year + 1 : year //下一个月的年份 let nowMonth = (parseInt(month) + 1) > 12 ? 1 : parseInt(month) + 1 //下一个月的月份 if (nextMonthNums) { //判定当前天数是否大于零 for (let i = 1; i <= nextMonthNums; i++) { let time = new Date(year, month - 1, i).toLocaleDateString() nextMonthDays.push({ date: i, //几号 week: this.data.weeksArr[new Date(nowYear, nowMonth - 1, i).getDay()], //星期几 time, isNowMonthDay: '' }); } } this.setData({ nextMonthDays }) console.log(nextMonthDays) },
- 下面渲染夏历,必要用到一个公共方法,这个方法很复杂,也很长,就不再这里展示了,你可以访问我的github堆栈下载源码获取这个方法. https://github.com/chenxuba/xx-calendar
- 页面内引入这个js
import calendarFormatter from "./index";
- 必要修改的是获取当月日期的这个方法,上下月都不展示,就不修改其他俩方法了,如果你必要请自行二开
getNowMonthDays(year, month) { let { nowMonth, nowDay } = this.data let nowMonthDays = [] let days = this.getThisMonthDays(year, month); //获取当月的天数 for (let i = 1; i <= days; i++) { let d = new Date(year, month - 1, i) let years = d.getFullYear() let months = d.getMonth() + 1 let day2 = d.getDate() let time = `${years+'/'+months +'/'+day2}` // 2023/3/3 let timer = time.replace(/\//g, "-") let timer2 = timer.split('-') var day = calendarFormatter.solar2lunar(timer2[0], timer2[1], timer2[2]); let newdate if (day.IDayCn == '月朔') { newdate = day.IMonthCn } else { newdate = day.IDayCn } nowMonthDays.push({ date: i, //几号 week: this.data.weeksArr[new Date(year, month - 1, i).getDay()], //星期几 time, color: false, day: newdate, isNowMonthDay: (month == nowMonth && i == nowDay) ? "isNowMonthDay" : "" }); } this.setData({ nowMonthDays }) console.log(nowMonthDays); },嗯~实现了
/** 切换月份 */ changeMonthFun(e){ let { year, month } = this.data let type = e.currentTarget.dataset.type //范例 if (type == 'prev') { //上一个月 year = month - 1 > 0 ? year : year - 1 month = month - 1 > 0 ? month - 1 : 12 } else { //next 下个月 year = (parseInt(month) + 1) > 12 ? year + 1 : year month = (parseInt(month) + 1) > 12 ? 1 : parseInt(month) + 1 } this.setData({ year, month, }) this.createDays(year, month) }
- 有点小瑕疵,不打紧,之前写静态页面的时间固定高度了,表明掉就可以了
selectDate(e){ let type = e.currentTarget.dataset.type //选择的时间范例 let index = e.currentTarget.dataset.index //选择的下标 let date = e.currentTarget.dataset.item.time //选择的下标 let selectDate = date.replace(/\//g, "-") console.log("选择的时间", selectDate) // 自定义变乱,父组件调用,回调 选择的时间selectDate this.triggerEvent('selectDate', selectDate) //将选择的时间范例的 isNowMonthDay 全改为'' this.data[type]?.forEach(item => { item.isNowMonthDay = '' }) this.data[type]?.forEach((item, idx) => { if (index == idx) { item.isNowMonthDay = (item.time == new Date().toLocaleDateString() ? "isNowMonthDay" : "isNotNowMonthDay"); //判定当前选中的日期是否是当前时间 } else { item.isNowMonthDay = '' } }) this.setData({ [type]: this.data[type], }) },
- 末了实现 已打卡日期的样式展示,要从父组件吸收一个已打卡日期数组,通过对比当月日期,来动态改变之前备用的color字段
- 先吸收一个数组
/** * 组件的属性列表 */ properties: { use_date_arr:{ type:Array, value:[] } },
this.data.use_date_arr.forEach(ele => { ele = ele.replace(/\-/g, "/") nowMonthDays.forEach(item => { if (ele == item.time) { console.log(item); item.color = true } }) })
data: { use_date_arr:['2023-3-1','2023-3-2','2023-3-3','2023-3-5','2023-3-8'] },<xx-calendar use_date_arr="{{use_date_arr}}"></xx-calendar>
- 源码地点 https://github.com/chenxuba/xx-calendar
|