在小程序倒数记日发布之后,收到很多用户的反馈,对于国人来说,很多人的生日是用传统农历来计算的,因此添加农历很有必要,但是小程序的选择框组件没有提供内建的农历支持,就只能靠自己来实现了。首先我们要先了解农历有哪些特点:

我国现行的农历是阴阳历,即以夏历(阳历)为主辅助阴历而成的,农历本身无法通过计算机获得所需要的日期,其闰年,闰月,每个月的天数都是没有明显规律的。

目前通常的处理办法是查表法,将1900~2100年的年份的特征值写死直接取用,这里推荐使用 JS文件下载

这个库能够获取基本的农历信息,也基本上是我们所需要的,现在我们开始着手做一个选择器,这里我们会使用到微信组件库里的 picker-view 来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
<view class='lunarPicker'>
<picker-view bindchange="bindChange" value="{{[year,month,day]}}">
<picker-view-column>
<view wx:for="{{lyears}}" wx:key="item" >{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{months}}" wx:key="item" >{{item}}</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{days}}" wx:key="item" >{{item}}</view>
</picker-view-column>
</picker-view>
</view>

lyears 是所有的年份列表, months 是选中的年份的月份列表, days 是选中的月份的天数列表

首先先获取 lyears

1
2
3
4
5
6
7
function lyearList() {
var list = [];
for (var i = 1900; i <= 2100; i++) {
list.push(i + calendar.toGanZhiYear(i))
}
return list
}

根据年份获取 months

1
2
3
4
5
6
7
8
9
10
11
function lmonthList(y) {
var monthList = [];
for (var i = 1; i <= 12; i++) {
monthList.push(calendar.toChinaMonth(i))
}
let leapMonth = calendar.leapMonth(y);
if (leapMonth) {
monthList.splice(leapMonth, 0, "闰" + calendar.toChinaMonth(leapMonth))
}
return monthList
}

根据月份和年份,以及月份是否为闰月来计算当前月的天数,可以得到 days

1
2
3
4
5
6
7
8
function ldaysList(y, m, isLeap) {
var dayList = [];
let dayCount = isLeap ? calendar.leapDays(y) : calendar.monthDays(y, m)
for (var i = 1; i <= dayCount; i++) {
dayList.push(calendar.toChinaDay(i))
}
return dayList
}

*以上三个方法可以添加到 calendar.js

初始化进入选择器的时候,我们可以默认选择日期为初始化的日期,即传入 picker-view 的value:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
onLoad: function (option) {
let initDate = new Date()
let initLunarDate = calendar.solar2lunar(initDate.getFullYear(), initDate.getMonth() + 1, initDate.getDate())

this.setData({
initLunarDate: initLunarDate,
})

this.setData({
month: calendar.getRightMonthIndex(originLunarDate.lYear, originLunarDate.lMonth, originLunarDate.isLeap) - 1,
day: initLunarDate.lDay - 1,
year: initLunarDate.lYear - 1900,
})
}

求月份的时候需要考虑到当前年是否有闰月,solar2lunar返回的是当月的月份值,(闰八月返回的是8,实际上这个是第九个月,接下来的九月实际上是第十个月)因此需要获得正确的index:

1
2
3
4
5
6
7
8
9
function getRightMonthIndex(y, m, isLeap) {
let leapMonth = calendar.leapMonth(y);
if (leapMonth) {
if (!(m < leapMonth || (m == leapMonth && !isLeap))) {
return m + 1
}
}
return m
}