自制简易日历

1. 日历插件的需求分析

在官网电商部分的开发中,遇到了需要自定义日历插件的情况,日历中的每一天都需要显示库存or价格,而此前使用的日历插件仅仅只有选择的功能,在这种情况下简单地研究了下日历的生成以及相关的一些兼容性问题。

所以经过简单的分析,简单总结:

  • 正确的日期显示以及排版
  • 响应某一个日期的点击事件
  • 随时对日历的月份进行修改(月份上移or下移),即重新渲染日历

2. 实际代码编写

2.1 参数约定

首先我们用一个对象来存储传入的参数,调出一个基本的当月日历,需要传入年、月份。
此外根据实际情况需要在每一天显示的内容,增加一个模板的参数,传入每一天所要显示的内容,传入HTML内容即可。
除了以上的最基本内容,我这里加入了日历的调整范围,即通过日历的上一月下一月按钮可以到达的最早的月份和最晚的月份。
得到的对象如下,这里我们在方法中先声明默认的值,在不传入任何参数的情况下,显示当前月份,并且将对日历月份没有任何限制。

1
2
3
4
5
6
var defaultSeeting = {
"year": new Date().getFullYear(),//年
"month": new Date().getMonth() + 1,//月
"template": "{{date}}",//日历表格中的模板
"refresh": false//是否非页面初始化,用以控制事件的绑定
}

这里面的模板template参数使用以下的规则进行替换:

1
2
3
4
5
6
7
8
9
10
/**
* @template 表格中一天的模板
* 模板替换规则:
* {{year}} -> 年
* {{month}} -> 月份
* {{date}} -> 日期
* {{fulldate}} -> 完整的日期
* {{day}} -> 周几
*
*/

2.2 日历的HTML渲染

我们要渲染的日历是一个table元素,所以本质上要处理的就是在一个7*57*4或者7*6的表格中,显示某月的每一个日期,根据表格是否属于该月来控制背景色,从单纯的展示功能来看,只要每一个td中显示的日期和背景颜色正确就可以了。所以我们预计效果图如下:

calendar_preview

先考虑要拼的HTML内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<table cellpadding="0">
<tbody>
<tr class="month">
<th colspan="7">
<div class="clearfix">
<div class="prevMonth">
<a class="prev0" href="javascript:;" title="上个月">上个月</a>
</div>
<div class="dates" data-fullmonth="2017-2">
<em>2017</em>年<em>2</em>月
</div>
<div class="nextMonth">
<a class="next" href="javascript:;" title="下个月">下个月</a>
</div>
</div>
</th>
</tr>
<tr class="week">
<th class="weekEnd"><span>星期日</span></th>
<th><span>星期一</span></th>
<th><span>星期二</span></th>
<th><span>星期三</span></th>
<th><span>星期四</span></th>
<th><span>星期五</span></th>
<th class="weekEnd"><span>星期六</span></th>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><p>1</p></td>
<td><p>2</p></td>
<td><p>3</p></td>
<td><p>4</p></td>
</tr>
//……
</tbody>
</table>

首先我们要获取这个月份有多少天,先以指定月份的次月1号为日期新建一个Date对象,再用这个对象的毫秒数减去一天的毫秒数(86400000)即为该月的最后一天,获取该天的日期就是我们指定的月份有多少天了。

1
2
var nextMonth1st = new Date(year, month, 1),//指定月份的次月1号
maxdays = (new Date(Date.parse(nextMonth1st) - 86400000)).getDate();

接下来就是日期td的渲染,需要判断对应的td是否为该月中的日期,其实只有以下的条件:

  • 小于当前月第一天的
  • 大于当前月最后一天的

对于日历来说,其实类似于一个二维的数组结构,所以我们只需要两层遍历去生成日历模板。

1
2
3
4
5
6
for (var j = 1; j <= 6; j++) {
//...
for (var k = 1; k <= 7; k++) {
//...
}
}

在判断的条件中我们用一个变量来存储当前处于星期几,即

1
2
3
4
5
6
7
8
var i1 = (new Date(y, m - 1 + i)).getDate(), i2 = 1;
for (var j = 1; j <= 6; j++) {
//...
for (var k = 1; k <= 7; k++) {
i2 = (j - 1) * 7 + k -i1;

}
}

// 断更待续