农历日期组件 【恋人小清单开发总结】
因为我过农历生日,所以开发了这个功能哈哈哈哈
自己说了算的感觉真好
言归正传
官方的日期组件不支持农历,所以需要借助官方的多列选择器做扩展
因为农历有闰年的缘故,在选择了年份后需要更新月份,选择了月份以后需要更新日期
另外一个需要注意的是闰年的情况下,多列选择器月份选中的索引需要注意一下,如果在闰月之前的月份索引需要减一,闰月之后的月份不需要减一
比如农历2020的四月,对应的月份索引应该等于3,闰4月对应的索引等于4.看下图片就明白了
看下效果图:
可以扫码体验

1、wxml代码
这里用到官方的多列选择器
<picker style="text-align: right;" data-type="lunar" name="lunarPicker"
bindchange="multiPickerChangeHandler"
bindcolumnchange="selectMultiPickerColumnHandler"
mode="multiSelector"
value="{{lunarDateRangeIndex}}"
range-key="text"
range="{{lunarDateRange}}">
<input readonly disabled placeholder="选择日期" placeholder-class="edit-placeholder" value="{{lunarDate}}"/>
</picker>
2、js
const lunarDate = require('../../utils/lunarDate.js');
const {calendar} = require('../../utils/calendar.js');
Component({
/**
* 组件的属性列表
*/
properties: {
lunarYear: Number,//农历年
lunarMonth: Number,//农历月
lunarDay: Number,//农历日
isLeapMonth: Boolean,//闰月标记
solarDate: String,//公历日期
solarDateRange: Object//公历年份起始
},
/**
* 组件的初始数据
*/
data: {
lunarDateRange: [],//农历日期范围
lunarDateRangeIndex: []//选中农历索引
},
ready: function () {
this._init();
},
/**
* 组件的方法列表
*/
methods: {
_init: function () {
const {
lunarYear,
lunarMonth,
lunarDay,
isLeapMonth,
solarDate,
solarDateRange
} = this.properties;
this._initLunarDateRange(solarDate, solarDateRange, lunarYear, lunarMonth, lunarDay, isLeapMonth);
},
/**
* 初始化农历日期数据
* @param solarDate
* @param solarDateRange
* @param lunarYear
* @param lunarMonth
* @param lunarDay
* @param isLeapMonth
* @private
*/
_initLunarDateRange: function (solarDate, solarDateRange, lunarYear, lunarMonth, lunarDay, isLeapMonth) {
const lunarDateRange = lunarDate.initLunarDateRangeHandler(solarDateRange);
const lunarDateRangeIndex = this._setDefaultLunarDateRangeIndex(lunarDateRange, solarDate, solarDateRange, lunarYear, lunarMonth, lunarDay, isLeapMonth);
this._updateLunarDateRange(lunarDateRange, lunarDateRangeIndex);
if (lunarYear && lunarMonth && lunarDay) {
console.log("农历日期不为空,准备显示农历日期");
this._showLunarDateHandler(lunarDateRange, lunarDateRangeIndex, false);
} else if (solarDate) {
console.log("公历日期不为空,准备显示转化后的农历日期");
this._showLunarDateHandler(lunarDateRange, lunarDateRangeIndex, true);
}
console.log("农历日期:", lunarDateRange);
},
/**
* 填充默认的农历日期选中索引
* 默认为当前日期
* @param lunarDateRange
* @param solarDate
* @param solarDateRange
* @param lunarYear
* @param lunarMonth
* @param lunarDay
* @param isLeapMonth
* @returns {*[]}
* @private
*/
_setDefaultLunarDateRangeIndex: function (lunarDateRange, solarDate, solarDateRange, lunarYear, lunarMonth, lunarDay, isLeapMonth) {
let lunarDateRangeIndex;
if (lunarYear && lunarMonth && lunarDay) {
console.log("外部传入农历日期:", lunarYear, lunarMonth, lunarDay, isLeapMonth);
lunarDateRangeIndex = [lunarYear - solarDateRange.start, this._getLunarMonthIndex(lunarYear, lunarMonth, isLeapMonth), lunarDay - 1];
} else {
console.log("外部传入公历日期:", solarDate);
let date = solarDate != null ? new Date(solarDate.replace(/-/g,"/")) : new Date();
// let date = new Date(solarDate.replace(/-/g,"/"));
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
const targetLunarDate = calendar.solar2lunar(year, month, day);
console.log("转化后的农历日期:", JSON.stringify(targetLunarDate));
const {lYear, lMonth, lDay, isLeap} = targetLunarDate;
lunarYear = lYear;
lunarMonth = lMonth;
isLeapMonth = isLeap;
lunarDateRangeIndex = [lYear - solarDateRange.start, this._getLunarMonthIndex(lunarYear, lunarMonth, isLeapMonth), lDay - 1];
}
lunarDateRange[1] = lunarDate.resetLunarMonthRangeHandler(lunarYear);
lunarDateRange[2] = lunarDate.resetLunarDayRangeHandler(lunarYear, lunarMonth, isLeapMonth);
console.log("默认的农历日期选中索引:", lunarDateRangeIndex);
return lunarDateRangeIndex;
},
/**
* 获取农历月份索引
* @param lunarYear
* @param lunarMonth
* @param isLeapMonth
* @returns {number}
* @private
*/
_getLunarMonthIndex: function (lunarYear, lunarMonth, isLeapMonth) {
const leapMonth = calendar.leapMonth(lunarYear);
//1、闰月索引不需要减一
//2、闰年、非闰月,并且当前月份在闰月之后,索引不需要减一
return (isLeapMonth || (!isLeapMonth && leapMonth > 0 && lunarMonth > leapMonth)) ? lunarMonth : lunarMonth - 1;
},
/**
* 更新农历日期选择范围、更新农历日期选中索引
* @param lunarDateRange
* @param lunarDateRangeIndex
* @private
*/
_updateLunarDateRange: function (lunarDateRange, lunarDateRangeIndex) {
this.setData({
lunarDateRange,
lunarDateRangeIndex
}, function () {
console.log("农历日期选择范围/农历日期选中索引更新完毕:", lunarDateRange, lunarDateRangeIndex)
});
},
/**
* 多列选择事件
* @param e
*/
selectMultiPickerColumnHandler: function (e) {
const {column, value} = e.detail;
let {lunarDateRange, lunarDateRangeIndex} = this.data;
let selectYear;
switch (column) {
case 0:
//选择年份,准备更新月份数据
selectYear = lunarDateRange[column][value].value;
console.log("选择年份:", selectYear);
const memoryLunarMonthRange = lunarDate.resetLunarMonthRangeHandler(selectYear);
lunarDateRange[1] = memoryLunarMonthRange;
//更新选中值
lunarDateRangeIndex = [value, 0, 0];
this._updateLunarDateRange(lunarDateRange, lunarDateRangeIndex);
break;
case 1:
//选择月份,准备更新天数数据
const {value: selectMonth, isLeapMonth} = lunarDateRange[column][value];
selectYear = lunarDateRange[0][lunarDateRangeIndex[0]].value;
console.log("选择年份:", selectYear, "选择月份:", selectMonth, "是否闰月:", isLeapMonth);
const memoryLunarDayRange = lunarDate.resetLunarDayRangeHandler(selectYear, selectMonth, isLeapMonth);
lunarDateRange[2] = memoryLunarDayRange;
//更新选中值
lunarDateRangeIndex = [lunarDateRangeIndex[0], value, 0];
this._updateLunarDateRange(lunarDateRange, lunarDateRangeIndex);
break;
default:
console.log("选择日:", lunarDateRange[column][value]);
break;
}
},
/**
* 选择农历日期
* @param e
*/
multiPickerChangeHandler: function (e) {
console.log('选择农历日期:', e);
const {value: selectValue} = e.detail;
const {lunarDateRange} = this.data;
this._showLunarDateHandler(lunarDateRange, selectValue, true);
},
/**
* 显示选中的农历日期
* @param lunarDateRange
* @param lunarDateRangeIndex
* @param doTriggerEvent 是否触发通知事件,告知父页面当前选中的农历日期
* @private
*/
_showLunarDateHandler: function (lunarDateRange, lunarDateRangeIndex, doTriggerEvent) {
const [lunarYearIndex, lunarMonthIndex, lunarDayIndex] = lunarDateRangeIndex;
const isLeapMonth = lunarDateRange[1][lunarMonthIndex].isLeapMonth;
this.setData({
lunarDate: lunarDateRange[0][lunarYearIndex].text + lunarDateRange[1][lunarMonthIndex].text + lunarDateRange[2][lunarDayIndex].text,
isLeapMonth,
lunarDateRangeIndex
}, function () {
if (doTriggerEvent) {
console.log("触发lunarDateConfirm事件");
this.triggerEvent("lunarDateConfirm", {
lunarYear: lunarDateRange[0][lunarYearIndex].value,
lunarMonth: lunarDateRange[1][lunarMonthIndex].value,
lunarDay: lunarDateRange[2][lunarDayIndex].value,
isLeapMonth
});
}
});
}
}
});
3、lunarDate.js
const {calendar} = require('/calendar.js');
/**
* 填充农历日期
* [@param](/user/param) solarDateRange
* [@returns](/user/returns) {Array}
*/
const initLunarDateRangeHandler = function (solarDateRange) {
console.log("公历日期范围:", solarDateRange);
const lunarDateRange = [];
const lunarYearRange = [], lunarMonthRange = [], lunarDayRange = [];
for (let i = solarDateRange.start; i <= solarDateRange.end; i++) {
lunarYearRange.push({text: calendar.toGanZhiYear(i) + '(' + i + ')', value: i});
}
for (let i = 1; i <= 12; i++) {
lunarMonthRange.push({text: calendar.toChinaMonth(i), value: i, isLeapMonth: false});
}
for (let i = 1; i <= 29; i++) {
lunarDayRange.push({text: calendar.toChinaDay(i), value: i});
}
lunarDateRange.push(lunarYearRange);
lunarDateRange.push(lunarMonthRange);
lunarDateRange.push(lunarDayRange);
console.log("农历日期:", lunarDateRange);
return lunarDateRange;
};
/**
* 重置农历月份
* [@param](/user/param) selectYear
* [@returns](/user/returns) {Array}
*/
const resetLunarMonthRangeHandler = function (selectYear) {
const leapMonth = calendar.leapMonth(selectYear);
const lunarMonthRange = [];
console.log("选择年份:", selectYear, "闰月:", leapMonth);
for (let i = 1; i <= 12; i++) {
lunarMonthRange.push({text: calendar.toChinaMonth(i), value: i, isLeapMonth: false});
}
if (leapMonth > 0) {
console.log("有闰月,准备更新月份数据");
lunarMonthRange.splice(leapMonth, 0, {
text: "闰" + calendar.toChinaMonth(leapMonth),
value: leapMonth,
isLeapMonth: true
});
}
return lunarMonthRange;
};
/**
* 重置农历日
* [@param](/user/param) selectYear
* [@param](/user/param) selectMonth
* [@param](/user/param) isLeapMonth
* [@returns](/user/returns) {Array}
*/
const resetLunarDayRangeHandler = function (selectYear, selectMonth, isLeapMonth) {
const lunarDayRange = [];
console.log("选择年份:", selectYear, "选择月份:", selectMonth, "是否闰月:", isLeapMonth);
const days = isLeapMonth ? calendar.leapDays(selectYear) : calendar.monthDays(selectYear, selectMonth);
for (let i = 1; i <= days; i++) {
lunarDayRange.push({text: calendar.toChinaDay(i), value: i});
}
return lunarDayRange;
};
module.exports = {initLunarDateRangeHandler, resetLunarMonthRangeHandler, resetLunarDayRangeHandler};
4、calendar.js(来自网上)
/**
* [@1900-2100](/user/1900-2100)区间内的公历、农历互转
* @charset UTF-8
* @Author Jea杨(JJonline@JJonline.Cn)
* @Time 2014-7-21
* @Time 2016-8-13 Fixed 2033hex、Attribution Annals
* @Time 2016-9-25 Fixed lunar LeapMonth Param Bug
* @Version 1.0.2
* @公历转农历:calendar.solar2lunar(1987,11,01); //[you can ignore params of prefix 0]
* @农历转公历:calendar.lunar2solar(1987,09,10); //[you can ignore params of prefix 0]
*/
const calendar = {
/**
* 农历1900-2100的润大小信息表
* @Array Of Property
* @return Hex
*/
lunarInfo: [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
/**Add By JJonline@JJonline.Cn**/
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],//2100
/**
* 公历每个月份的天数普通表
* @Array Of Property
* @return Number
*/
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
/**
* 天干地支之天干速查表
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
* @return Cn string
*/
Gan: ["\u7532", "\u4e59", "\u4e19", "\u4e01", "\u620a", "\u5df1", "\u5e9a", "\u8f9b", "\u58ec", "\u7678"],
/**
* 天干地支之地支速查表
* @Array Of Property
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
* @return Cn string
*/
Zhi: ["\u5b50", "\u4e11", "\u5bc5", "\u536f", "\u8fb0", "\u5df3", "\u5348", "\u672a", "\u7533", "\u9149", "\u620c", "\u4ea5"],
/**
* 天干地支之地支速查表<=>生肖
* @Array Of Property
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
* @return Cn string
*/
Animals: ["\u9f20", "\u725b", "\u864e", "\u5154", "\u9f99", "\u86c7", "\u9a6c", "\u7f8a", "\u7334", "\u9e21", "\u72d7", "\u732a"],
/**
* 24节气速查表
* @Array Of Property
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
* @return Cn string
*/
solarTerm: ["\u5c0f\u5bd2", "\u5927\u5bd2", "\u7acb\u6625", "\u96e8\u6c34", "\u60ca\u86f0", "\u6625\u5206", "\u6e05\u660e", "\u8c37\u96e8", "\u7acb\u590f", "\u5c0f\u6ee1", "\u8292\u79cd", "\u590f\u81f3", "\u5c0f\u6691", "\u5927\u6691", "\u7acb\u79cb", "\u5904\u6691", "\u767d\u9732", "\u79cb\u5206", "\u5bd2\u9732", "\u971c\u964d", "\u7acb\u51ac", "\u5c0f\u96ea", "\u5927\u96ea", "\u51ac\u81f3"],
/**
* 1900-2100各年的24节气日期速查表
* @Array Of Property
* @return 0x string For splice
*/
sTermInfo: ['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', '9...
1 回复

