手写Vue日历组件
前言
提起日历组件,第一感觉就是不想写,有太多现有的日历组件可以供你选择。前几天的一个项目需求,现有的组件无法提供完善的日历服务,便自己操刀动手写了一个日历组件,才发现这个东西很好实现(完全不明白为啥看到日历这两字就觉得难呢)。废话不说,先看效果图:
思路
日历面板分三个模块,顶部操作模块、星期展示模块以及最重要的日历展示模块。前两个模块暂且不提(一个数组加个几个按钮 =-=),日历展示模块大家可以看出,除了本月的日期,一般每个日历面板都包含上个月填充的几天以及下个月填充的几天来共同构成了日历日期数组,切换月份自然也就是重构数组数据,那我们怎么来组合这个数组数据呢?大家来看:
- 本月第一天(1号)是周几,上个月也就填充几天(发现没有=_=),同样的,下个月填充的天数也就有了。而本月的日期可以通过获取本月最后一天的日期来获取,面板数据有木有?
- 接下来数据有了自然就要实现上下月的切换了,怎么整?当然是和上边一样了,所以,我们要封装一个根据年月来获取日历面板数据的方法,这样会很方便。
- 公历的日历面板基本完成,日历日历的点击事件根据业务需求自己添加就好,重点是农历怎么写?我当时同样一脸懵逼,然后就去百度了一下农历,想总结一下规律看能不能找到一点思路,然后十天干十二地支二十四节气整的更懵逼了,后来看了一下别人的实现才发现,嗯,好家伙,直接把1900-2100年的闰月信息,节气速查表都拿来了。在没有更好的办法(没有深厚的易经功底)之下,这也算一个好办法~这样子,我们就可以同样封装一个方法,通过年月日来获取对应的农历日期
- 农历的具体封装下边细聊,说到现在大家发现没有,日历面板的每个日期都会有很多属性,包括年,月,日,农历日期,是否选中,是否为当天,是否禁用,节假日。甚至生肖,天干地支你也值拥有,这样,我们就需要一个专门通过年月日来组装相应的数据的方法。而怎样才能才点击日期的时候快速更改对应的状态呢?这便是我们需要考虑好的数据格式。我的方法便是通过对象key存储对应日期,value存储对应的日期数据,这样我便能快速查找,也就是对象里边包裹对象,而通过for of循环同样可以满足我的组件渲染问题,好了,皆大欢喜~
实现
- 将日期对象转换为yyyy-mm-dd的字符串
formatTimeToString(newDate: any) { const year = newDate.getFullYear(); let month: number | string = newDate.getMonth() + 1; let date: number | string = newDate.getDate(); month = month < 10 ? "0" + month : month; date = date < 10 ? "0" + date : date; return `${year}-${month}-${date}`; }
- 返回组装数据
// 根据时间返回对应初始状态 formatDate(year: number, month: number, day: number) { const { year: nowYear, month: nowMonth, date: nowDay } = this.nowDate; const dateString = this.formatTimeToString(new Date(year, month - 1, day)); // Lunar 获取相应农历方法 const lunarClass = new Lunar(); const lunar = lunarClass.getLunarDate(dateString); const dateObj = { year: year, month: month, day: day, isToday: "", isChecked: "", isDisable: "", lunar: "", lunarMonth: lunar.month, lunarDay: lunar.day, animal: lunar.animal, ganZhi: lunar.ganZhi, holiday: lunar.holiday }; // 初一显示农历月份 let lunarStr = dateObj.lunarDay === "初一" ? dateObj.lunarMonth : dateObj.lunarDay; // 有节假日,根据权重显示节假日 if (dateObj.holiday && dateObj.holiday.length) { let sort = 0; dateObj.holiday.map((item: { name: string; sort: number }) => { if (item.sort > sort) { sort = item.sort; lunarStr = item.name; } }); } dateObj.lunar = lunarStr; // 是否为今日 if ( new Date(year, month - 1, day).getTime() === new Date(nowYear, +nowMonth - 1, +nowDay).getTime() ) { dateObj.isToday = "today"; } // isLastStatus: 今日之前的日期是否可选 if (!this.isLastStatus) { if ( new Date(year, month - 1, day).getTime() < new Date(nowYear, +nowMonth - 1, +nowDay).getTime() ) { dateObj.isDisable = "disabled"; } } // checkedList: 已选日期 if ( this.checkedList && this.checkedList.length && this.checkedList.indexOf(dateString) > -1 ) { dateObj.isChecked = "checked"; } return dateObj; }
- 当月面板数据
getDateList(year: number, month: number) { let dateList: any = {}; // 头部补齐的天数 = 本月第一天是星期几 const fillHeaderDays = new Date(year, month - 1, 1).getDay(); // 上个月最后一天 const MonthLastDate = new Date(year, month - 1, 0).getDate(); // 本月最后一天 const MonthDate = new Date(year, month, 0).getDate(); // 下个月第一天是星期几 let currentNextMonthFirstDay = new Date(year, +month, 1).getDay(); // 需要末尾补齐的天数 const fillFooterDays = currentNextMonthFirstDay === 0 ? 0 : 7 - currentNextMonthFirstDay; // 上个月补充天数 for (let header = fillHeaderDays; header > 0; header--) { const date = this.formatTimeToString( new Date(year, month - 2, MonthLastDate - header + 1) ); dateList[date] = this.formatDate( year, month - 1, MonthLastDate - header + 1 ); } // 当前月天数 for (let middle = 0; middle < MonthDate; middle++) { const date = this.formatTimeToString( new Date(year, month - 1, middle + 1) ); dateList[date] = this.formatDate(year, month, middle + 1); } // 下个月补充天数 for (let footer = 0; footer < fillFooterDays; footer++) { const date = this.formatTimeToString(new Date(year, month, 1 + footer)); dateList[date] = this.formatDate(year, month + 1, 1 + footer); } this.daysList = dateList; }
- 农历日期获取
export class Lunar { // 初一显示月份 // 节日按照优先级替换日 private dataObj: any = { month: "", day: "", holiday: [], animal: "", ganZhi: "" }; // 闰几月 private leapM: number = 0; // 当前年份的农历num private leapNumber: number = 0; // 天干 private Gan: Array<string> = [ "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" ]; // 地支 private Zhi: Array<string> = [ "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" ]; // 生肖 private Animal: Array<string> = [ "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" ]; private Ten: Array<string> = ["初", "十", "廿", "卅"]; private Number: Array<string> = [ "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二" ]; private leapMonthName: Array<string> = [ "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" ]; private lunarHoliday: Array<{ date: string; name: string; sort: number; }> = [ { date: "01-01", name: "春节", sort: 3 }, { date: "01-15", name: "元宵节", sort: 3 }, { date: "05-05", name: "端午节", sort: 2 }, { date: "07-07", name: "七夕节", sort: 2 }, { date: "08-15", name: "中秋节", sort: 2 }, { date: "09-09", name: "重阳节", sort: 2 }, { date: "12-08", name: "腊八", sort: 2 }, { date: "12-24", name: "小年", sort: 2 } ]; private solarHoliday: Array<{ date: string; name: string; sort: number; }> = [ { date: "01-01", name: "元旦", sort: 3 }, { date: "02-14", name: "情人节", sort: 3 }, { date: "03-18", name: "妇女节", sort: 2 }, { date: "03-12", name: "植树节", sort: 2 }, { date: "04-01", name: "愚人节", sort: 2 }, { date: "05-01", name: "劳动节", sort: 2 }, { date: "06-01", name: "儿童节", sort: 2 }, { date: "07-01", name: "建党节", sort: 2 }, { date: "08-01", name: "建军节", sort: 2 }, { date: "09-10", name: "教师节", sort: 2 }, { date: "10-01", name: "国庆节", sort: 2 }, { date: "11-01", name: "万圣节", sort: 2 }, { date: "12-25", name: "圣诞节", sort: 2 } ]; // 1980年的数据是: 0x095b0 // 0000 1001 0101 1011 0000 // 1-4: 表示当年有无闰年,有的话,为道闰月的月份,没有的话,为0。 // 5-16:为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。 // 17-20:表示闰月是大月还是小月,仅当存在闰月的情况下有意义 // 表示1980年没有闰月,从1月到12月的天数依次为:30,29,29,30,29,30,29,30,30,29,30,30 // 农历历月的天数只有29日和30日两种 // 农历1900-2100的润大小信息表 private lunarInfo: Array<number> = [ 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, //1900-1909 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, //1910-1919 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, //1920-1929 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, //1930-1939 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, //1940-1949 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, //1950-1959 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, //1960-1969 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, //1970-1979 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //1980-1989 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, //1990-1999 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029 0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049 0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059 0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069 0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079 0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089 0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099 0x0d520 ]; // 1900-2100各年的24节气日期速查表 private sTermInfo: Array<string> = [ "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "9778397bd19801ec9210c965cc920e", "97b6b97bd19801ec95f8c965cc920f", "97bd09801d98082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2", "9778397bd197c36c9210c9274c91aa", "97b6b97bd19801ec95f8c965cc920e", "97bd09801d98082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec95f8c965cc920e", "97bcf97c3598082c95f8e1cfcc920f", "97bd097bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd097bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd097bd07f595b0b6fc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "9778397bd19801ec9210c9274c920e", "97b6b97bd19801ec95f8c965cc920f", "97bd07f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c920e", "97b6b97bd19801ec95f8c965cc920f", "97bd07f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bd07f1487f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf7f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c9274c920e", "97bcf7f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c91aa", "97b6b97bd197c36c9210c9274c920e", "97bcf7f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "9778397bd097c36c9210c9274c920e", "97b6b7f0e47f531b0723b0b6fb0722", "7f0e37f5307f595b0b0bc920fb0722", "7f0e397bd097c36b0b6fc9210c8dc2", "9778397bd097c36b0b70c9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e37f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc9210c8dc2", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9274c91aa", "97b6b7f0e47f531b0723b0787b0721", "7f0e27f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c91aa", "97b6b7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "9778397bd097c36b0b6fc9210c8dc2", "977837f0e37f149b0723b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f5307f595b0b0bc920fb0722", "7f0e397bd097c35b0b6fc9210c8dc2", "977837f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e37f1487f595b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc9210c8dc2", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd097c35b0b6fc920fb0722", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0787b06bd", "7f07e7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0b0bb0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14998082b0723b06bd", "7f07e7f0e37f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722", "7f0e397bd07f595b0b0bc920fb0722", "977837f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f1487f595b0b0bb0b6fb0722", "7f0e37f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e37f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e37f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f149b0723b0787b0721", "7f0e27f1487f531b0b0bb0b6fb0722", "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0723b06bd", "7f07e7f0e47f149b0723b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722", "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14998082b0723b06bd", "7f07e7f0e37f14998083b0787b0721", "7f0e27f0e47f531b0723b0b6fb0722", "7f0e37f0e366aa89801eb072297c35", "7ec967f0e37f14898082b0723b02d5", "7f07e7f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e36665b66aa89801e9808297c35", "665f67f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b0721", "7f07e7f0e47f531b0723b0b6fb0722", "7f0e36665b66a449801e9808297c35", "665f67f0e37f14898082b0723b02d5", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e36665b66a449801e9808297c35", "665f67f0e37f14898082b072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e26665b66a449801e9808297c35", "665f67f0e37f1489801eb072297c35", "7ec967f0e37f14998082b0787b06bd", "7f07e7f0e47f531b0723b0b6fb0721", "7f0e27f1487f531b0b0bb0b6fb0722" ]; private jieQi: Array<string> = [ "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至" ]; // 构造函数,实例化类的时候触发的方法 getLunarDate(dateString: string) { const { year, month, date } = this.formatTimeToObj(dateString); this.solarHoliday.map( (item: { name: string; sort: number; date: string }) => { let m = +item.date.split("-")[0]; let d = +item.date.split("-")[1]; if (m === month && d === date) { this.dataObj.holiday.push({ name: item.name, sort: item.sort }); } } ); if (date === this.getTerm(year, month * 2 - 1)) { this.dataObj.holiday.push({ name: this.jieQi[month * 2 - 2], sort: 1 }); } if (date === this.getTerm(year, month * 2)) { this.dataObj.holiday.push({ name: this.jieQi[month * 2 - 1], sort: 1 }); } this.getTerm(year, month * 2); return this.getLunarDateString(year, month, date); } // 返回农历y年一整年的总天数 private yearDays(y: number) { let i, sum = 348; for (i = 0x8000; i > 0x8; i >>= 1) { if ((this.lunarInfo[y - 1900] & i) !== 0) sum += 1; } return sum + this.leapDays(y); } // 返回农历y年闰月的天数 若该年没有闰月则返回0 private leapDays(y: number) { if (this.leapMonth(y)) return (this.lunarInfo[y - 1900] & 0x10000) != 0 ? 30 : 29; else return 0; } // 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法 private monthDays(y: number, m: number) { if (m > 12 || m < 1) return -1; return this.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29; } // 返回农历y年闰月是哪个月;若y年没有闰月 则返回0 private leapMonth(y: number) { return this.lunarInfo[y - 1900] & 0b1111; } // 传回农历 y年的生肖 private animalsYear(y: number) { return this.Animal[(y - 4) % 12]; } // 传入月日的offset 传回干支 private returnGanZhi(y: number) { // 甲子年(1864) let num = y - 1900 + 36; return this.Gan[num % 10] + this.Zhi[num % 12]; } // 传入农历天数返回农历日期 private returnDayString(d: number) { let n = d % 10 === 0 ? 9 : (d % 10) - 1; if (d > 30 || d < 1) return ""; if (d == 10) return "初十"; else return this.Ten[Math.floor(d / 10)] + this.Number[n]; } // 传入公历日期返回年月日 private formatTimeToObj(dateString: string) { const newDate = new Date(dateString); const year = newDate.getFullYear(); let month: number | string = newDate.getMonth() + 1; let date: number | string = newDate.getDate(); return { year, month, date }; } // 获取农历日期 private getLunarDateString(y: number, m: number, d: number) { if (y < 1900 || y > 2100) return -1; if (y === 1900 && m === 1 && d < 31) return -1; let i, leap = 0, temp = 0; // 距离1900年天数 let offset = (Date.UTC(y, m - 1, d) - Date.UTC(1900, 0, 31)) / 86400000; // 从1900年开始推算到今天的农历时间 for (i = 1900; i < 2101 && offset > 0; i++) { temp = this.yearDays(i); offset -= temp; } if (offset < 0) { offset += temp; i--; } this.leapNumber = offset; //农历年 let year = i; //闰哪个月 leap = this.leapMonth(i); if (leap > 0) this.leapM = leap; let isLeap = false; //效验闰月 for (i = 1; i < 13 && offset > 0; i++) { //闰月 if (leap > 0 && i === leap + 1 && isLeap === false) { --i; isLeap = true; temp = this.leapDays(year); //计算农历闰月天数 } else { temp = this.monthDays(year, i); //计算农历普通月天数 } //解除闰月 if (isLeap === true && i === leap + 1) isLeap = false; offset -= temp; } if (offset === 0 && leap > 0 && i === leap + 1) { if (isLeap) { isLeap = false; } else { isLeap = true; --i; } } if (offset < 0) { offset += temp; --i; } let month = i; let day = offset + 1; // 判断是否+闰 let status = false; if ( day === 1 && this.leapM > 0 && this.leapNumber > (month - 1) * 30 && this.leapM === month ) { status = true; } this.lunarHoliday.map( (item: { name: string; sort: number; date: string }) => { let m = +item.date.split("-")[0]; let d = +item.date.split("-")[1]; if (m === month && d === day) { this.dataObj.holiday.push({ name: item.name, sort: item.sort }); } } ); this.dataObj.month = this.getLeapMonthName(month, status); this.dataObj.day = this.returnDayString(day); this.dataObj.animal = this.animalsYear(year); this.dataObj.ganZhi = this.returnGanZhi(year); return this.dataObj; } // 传入公历y年获得该年第n个节气的公历日期 // y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起 private getTerm(y: number, n: number) { if (y < 1900 || y > 2100) return -1; if (n < 1 || n > 24) return -1; var _table = this.sTermInfo[y - 1900]; var _info = [ parseInt("0x" + _table.substr(0, 5)).toString(), parseInt("0x" + _table.substr(5, 5)).toString(), parseInt("0x" + _table.substr(10, 5)).toString(), parseInt("0x" + _table.substr(15, 5)).toString(), parseInt("0x" + _table.substr(20, 5)).toString(), parseInt("0x" + _table.substr(25, 5)).toString() ]; var _calday = [ _info[0].substr(0, 1), _info[0].substr(1, 2), _info[0].substr(3, 1), _info[0].substr(4, 2), _info[1].substr(0, 1), _info[1].substr(1, 2), _info[1].substr(3, 1), _info[1].substr(4, 2), _info[2].substr(0, 1), _info[2].substr(1, 2), _info[2].substr(3, 1), _info[2].substr(4, 2), _info[3].substr(0, 1), _info[3].substr(1, 2), _info[3].substr(3, 1), _info[3].substr(4, 2), _info[4].substr(0, 1), _info[4].substr(1, 2), _info[4].substr(3, 1), _info[4].substr(4, 2), _info[5].substr(0, 1), _info[5].substr(1, 2), _info[5].substr(3, 1), _info[5].substr(4, 2) ]; return parseInt(_calday[n - 1]); } // 农历名称 private getLeapMonthName(m: number, status = false) { if (m > 12 || m < 1) return -1; let s = ""; if (status) s += "闰"; s += this.leapMonthName[m - 1]; s += "月"; return s; } }
补充
- 根据时间格化为描述年月日的对象
formatTimeToObj(newDate: any) { const year = newDate.getFullYear(); let month: number | string = newDate.getMonth() + 1; let date: number | string = newDate.getDate(); const day = newDate.getDay(); month = month < 10 ? "0" + month : month; date = date < 10 ? "0" + date : date; return { year, month, date, day }; }
- 日历切换
handleToNextMonth() { const { year, month } = this.showDate; this.showDate = this.formatTimeToObj(new Date(year, +month)); this.getDateList(this.showDate.year, +this.showDate.month); } handleToLastMonth() { const { year, month } = this.showDate; this.showDate = this.formatTimeToObj(new Date(year, +month - 2)); this.getDateList(this.showDate.year, +this.showDate.month); }
- 初始化定义数据
private weekTabs = { 0: "日", 1: "一", 2: "二", 3: "三", 4: "四", 5: "五", 6: "六" }; private daysList: any = {}; private checkedList: Array<string> = []; // 当前时间 nowDate = this.formatTimeToObj(new Date()); //正在展示的时间,初始化为当前时间 showDate = this.formatTimeToObj(new Date());
总结
日历组件已经完美实现,当然,日历的点击时事件可以在这基础上去完善,我相信这个日历组件已经基本可以满足大家的需求,有更好的办法也希望大家多多指教。