基于ant

您所在的位置:网站首页 显示农历的时间插件 基于ant

基于ant

2024-07-15 21:33| 来源: 网络整理| 查看: 265

    最近在用ant-design-vue开发过程中,想使用农历日历,不过现有的Calendar暂时不支持农历日历,于是基于ant-design-vue的组件Calendar,再此基础上进行扩展开发了一个简易的农历日历组件。

    核心思想就是有一个数组记录1900~2049之间每个农历年的信息(这些信息包括每个月的天数、闰月月份、闰月天数),取到公历日期后,计算此日期与公历1900年1月30日0时的差距天数(该天是农历1900年正月初一的前一天),根据差距天数计算出当前日期的农历日期。

    目前仅支持1900~2049年的农历日期,另外当前也比较简易,算法可以继续优化,功能也可以进行扩展,有需要可以再次基础进行扩展。

    下面直接贴出代码,代码就两个文件,一个.vue文件一个.js文件,代码中有注释,逻辑比较清晰。

    js文件:

/** * 每一年的农历信息共计存储在5位十六制数中,即20位二进制数中 * 1111 1111 1111 1111 1111 * 高3位暂时空置,第4位当该年是闰年时标志该年闰月是大月(30天)还是小月(29天),是大月则标志位为1 * 低4位用来标志该年闰月是哪一月份 * 中间12位由高到低依次用来标志该年1~12月份分别是大月(30天)还是小月(29天),是大月则标志位为1 */ const LUNAR_INFO = [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, 0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, 0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, 0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, 0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, 0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, 0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, 0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, 0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, 0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, 0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, 0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, 0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, 0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, 0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0]; const LUNAR_MONTH_NUMBER = ["正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊"]; const CHINESE_NUMBER = ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十"]; const CHINESE_ZODIAC = ["鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"]; const HEAVENLY_STEMS = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]; const EARTHLY_BRANCHES = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]; const CHINESE_TEN = ["初", "十", "廿", "卅"]; /** * 公历1900年1月30日0时的时间戳,该天是农历1900年正月初一的前一天 */ const START_DATE_MS = -2206512343000; /** * 最小和最大允许的公历日期范围 * 农历1900年正与初一和农历1949年腊月廿九 */ const MIN_LUNAR_DATE_MS = -2206425943000; const MAX_LUNAR_DATE_MS = 2526480000000; export default class Lunar { constructor(moment) { let time = moment.valueOf(); if (time < MIN_LUNAR_DATE_MS || time >= MAX_LUNAR_DATE_MS) { throw new Error("date out of range,the range is 1900-01-31 ~ 2050-01-22"); } //求出和1900年1月30日相差的天数 let offset = parseInt((time - START_DATE_MS) / 86400000); //依次获取每农历年的天数,用offset减去每年天数 //当offset小于当年总天数时,则当年即为该日期所属年份,剩余offset即为该年的第几天 let iYear, daysOfYear; for (iYear = 1900; iYear < 2050; iYear++) { daysOfYear = Lunar.getYearDays(iYear); if (offset > daysOfYear) { offset -= daysOfYear; } else { break; } } // 农历年份 this.year = iYear; this.leapMonth = Lunar.getLeapMonth(iYear); // 闰哪个月,1-12 //用当年的天数offset,逐个减去每月(农历)的天数 //当offset小于当月总天数时,则当月即为该日期所属月份,求出当天是本月的第几天 //当该年为闰年是,遍历到闰月月份后,需减去闰月总天数,并标记该月是闰月 let iMonth, daysOfMonth; for (iMonth = 1; iMonth < 13; iMonth++) { daysOfMonth = Lunar.getMonthDays(this.year, iMonth); if (offset > daysOfMonth) { offset -= daysOfMonth; } else { break; } //如果当前月份与闰月月份一致时开始处理闰月数据 if (iMonth === this.leapMonth) { daysOfMonth = Lunar.getLeapMonthDays(this.year); if (offset > daysOfMonth) { offset -= daysOfMonth; } else { this.isLeapMonth = true; break; } } } this.month = iMonth; this.day = offset; } /** * 获取农历年份 * @author bawy * @date 2019/11/4 22:56 * @return 农历年份 */ getLunarYear() { return this.year; } /** * 获取农历月份 * @author bawy * @date 2019/11/4 22:56 * @return 农历月份 */ getLunarMonth() { return this.month; } /** * 获取农历天数 * @author bawy * @date 2019/11/4 22:56 * @return 农历天数 */ getLunarDay() { return this.day; } /** * 获取中文农历日期 * @author bawy * @date 2019/11/7 0:51 * @return 中文农历日期 */ getChineseLunarDay() { if (this.day === 1) { return (this.isLeapMonth === true ? '闰' :'') + LUNAR_MONTH_NUMBER[this.month - 1] + '月'; } return Lunar.getChinaDayString(this.day); } /** * 是否闰年 * @author bawy * @date 2019/11/4 22:55 * @return 是闰年返回true */ isLeap() { return this.leapMonth > 0; } /** * 当前日期所属月份是否为闰月 * @author bawy * @date 2019/11/4 22:55 * @return 是则返回true */ isLeapMonth() { return this.isLeapMonth === true; } /** * 获取当前日期所属年份生肖 * @author bawy * @date 2019/11/4 22:55 * @return 生肖 */ getChinesZodiac() { return Lunar.getChinesZodiac(this.year); } /** * 获取当前农历日期的天干地支 * @author bawy * @date 2019/11/4 22:56 * @return 当前农历日期的天干地支 */ getChineseEra() { return Lunar.getChineseEra(this.year); } /** * 获取农历 y 年的总天数 * 基础天数为12*29=348天 * 遍历该年份每个月是大月还是小月,大月则在基础天数上增加一天 * 获取该年闰月天数,加上闰月天数得到该年总天数 * @author bawy * @date 2019/11/4 22:56 * @param y 年份 * @return 总天数 */ static getYearDays(y) { let i, sum = 348; for (i = 0x8000; i > 0x8; i >>= 1) { if ((LUNAR_INFO[y - 1900] & i) !== 0) { sum += 1; } } return (sum + Lunar.getLeapMonthDays(y)); } /** * 获取农历 y 年闰月的天数(29或30天),没有闰月返回0 * 判断该年份是否存在闰月 * 如果存在闰月,提取闰月标志位,如果为1(大月)则返回30,反之返回29 * @author bawy * @date 2019/11/4 22:56 * @param y 年份 * @return 闰月的天数 */ static getLeapMonthDays(y) { if (Lunar.getLeapMonth(y) === 0) { return 0; } else { if ((LUNAR_INFO[y - 1900] & 0x10000) === 0) { return 29; } else { return 30; } } } /** * 获取农历 y 年闰哪个月1-12,没闰月返回0 * 取出指定年份信息的后四位,对应的值即为闰月的月份 * @author bawy * @date 2019/11/4 22:57 * @param y 年份 * @return 闰月月份 */ static getLeapMonth(y) { return LUNAR_INFO[y - 1900] & 0xf; } /** * 获取指定农历 y 年 m 月的总天数(29或30天) * 提取指定年份信息中指定月份的标志位,标志位为1则返回30否则返回29 * @author bawy * @date 2019/11/4 22:57 * @param y 年份 * @param m 月份 * @return 该年该月总天数 */ static getMonthDays(y, m) { if ((LUNAR_INFO[y - 1900] & (0x10000 >> m)) === 0) { return 29; } else { return 30; } } /** * 获取指定农历年份对应的生肖 * @author bawy * @date 2019/11/4 22:57 * @param y 农历年份 * @return 生肖 */ static getChinesZodiac(y) { return CHINESE_ZODIAC[(y - 4) % 12]; } /** * 获取指定农历年份的天干地支 * 1864年是甲子年,作为0坐标,根据偏移量计算天干地支 * @author bawy * @date 2019/11/4 22:57 * @param y 农历年份 * @return 天干地支 */ static getChineseEra(y) { let num = y - 1864; return (HEAVENLY_STEMS[num % 10] + EARTHLY_BRANCHES[num % 12]); } /** * 指定日期转为中文 * @author bawy * @date 2019/11/4 22:57 * @param day 日期天数 * @return 中文日期 */ static getChinaDayString(day) { if (day > 30) { throw new Error("the lunar month most has 30 days"); } if (day === 10) { return "初十"; } else { let n = day % 10 === 0 ? 9 : day % 10 - 1; return CHINESE_TEN[parseInt(day / 10)] + CHINESE_NUMBER[n]; } } }

    vue文件:

{{getDate(text)}} {{getLunarDate(text)}} import moment from "moment"; import Lunar from "./lunar"; import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN'; export default { name: "LunarCalendar", data() { return { locale: zhCN, today: null, currentMonth: 0, selectDate: null } }, props: { width: { type: Number, required: false, default() { return 422; } } }, methods: { onPanelChange(value, mode) { this.currentMonth = parseInt(value.format("M")); }, onDateChange(value) { this.selectDate = value; if (parseInt(value.format("M")) !== this.currentMonth) { this.currentMonth = parseInt(value.format("M")); } }, getClass(value) { let classStr = "lunar-date-cell"; if (value.format("YYYY-MM-DD") === this.today.format("YYYY-MM-DD")) { classStr += " lunar-date-cell-today" } let month = parseInt(value.format("M")); if (month === this.currentMonth - 1 || (month === 12 && this.currentMonth === 1)) { classStr += " lunar-date-cell-last-month" } if (month === this.currentMonth + 1 || (month === 1 && this.currentMonth === 12)) { classStr += " lunar-date-cell-next-month" } if (this.selectDate && value.format("YYYY-MM-DD") === this.selectDate.format("YYYY-MM-DD")) { classStr += " lunar-date-cell-selected-day" } return classStr; }, getDate(value) { return value.format("D"); }, getLunarDate(value) { let lunar = new Lunar(value); return lunar.getChineseLunarDay(); } }, created() { this.today = new moment(); this.currentMonth = parseInt(this.today.format("M")); } } .lunar-date-cell { text-align: center; } .lunar-date-cell:hover { background: #e6f7ff; cursor: pointer; } .lunar-date-cell-today { box-shadow: 0 0 0 1px #1890ff inset; } .lunar-date-cell-selected-day { color: #fff; background: #1890ff; } //上一个月的日期单元格 .lunar-date-cell-last-month { color: rgba(0, 0, 0, 0.25); } //下一个月的日期单元格 .lunar-date-cell-next-month { color: rgba(0, 0, 0, 0.25); } //公历日期样式 .calendar-date { font-weight: bold; }

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3