首页 > 安全资讯 >

javascript动手写日历组件(1)——构建日历逻辑 (by vczero)

14-08-10

一、分析日历的组成部分和交互要素(1)组成部分:选择年月部分、星期显示、包含本月(或者有前月和下一个月部分日子)(2)根据选择的年和月份,动态绘制日历面板。(3)一个日历 7(天) * 5(周) = 35格

一、分析日历的组成部分和交互要素
 
(1)组成部分:选择年月部分、星期显示、包含本月(或者有前月和下一个月部分日子)
 
(2)根据选择的年和月份,动态绘制日历面板。
 
(3)一个日历 7(天) * 5(周) = 35格表格。
 
(4)一个月份是统一的一个面板;一个月的头一天一定在日历面板的第一行,根据该天的“星期几”确定位置。
 
(5)第一格子是星期一,最后一个格子是星期日,为5周的日历面板。
 
二、确定逻辑设计
 
 
 
日历上面的日历,8月1号建军节为什么会出现在这一格?因为一个月的天数是小于5周(35天)的,因此,在第一行肯定包含了一个月份的第一天,而这一天的位置是根据该天的星期几来确定的,比如7月的1号是星期二,那么7月1号在第一行的星期二的位置上,然后依次类推,计算前一个月在面板上显示的日期,下一个月在面板上显示的日期。
 
可以将每一个表格看成是一个日期对象,那么下一步的目的就是根据传入不同年份和月份,计算出面板上显示的日期对象数组。
 
三、构建日历类
 
(1)首先,构建一个可以传入DOM DIV的日历类。
 
1 var Calendar = function(div){
2     this.div = document.getElementById(div);
3 };
5 Calendar.week = ['星期一', '星期二','星期三', '星期四','星期五', '星期六', '星期日'];
6 Calendar.month = ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'];
(2)日历面板逻辑实现。
 
一个日历面板包含3个日期对象数组,第一个是preMonth,因为,也许该日历面板上会显示前一个月的一些日期;第二个是本月的日期currentMonth;第三个是下一个月的日期数组,nextMonth。定义一个函数monthPanel代表一个日历面板,返回值是三个数组合并的对象。
 
如何计算前一个月会显示多少日期?首先计算选择的月份的第一天在第一行(从0开始计算)占据着第几个位置(4),然后上一个月的总天数(31)减去该位置向上索取,即31-4,31-3,31-2,31-1,31.,那么结果就是31-4,31-3,31-2,31-1,31, 1。
 
如何计算下一个月会显示多少日期?很好办,总共35个格子,那么35 - 当前月份的天数 - 当前月份占据的位置n+1 就是要显示的下一个的日期格子数。
 
综合后的代码如下:
 
复制代码
 1 Calendar.prototype.monthPanel = function(date){
 2     //如果传递了Date对象,则按Date对象进行计算月份面板
 3     //否则,按照当前月份计算面板
 4     var date = date || new Date(),
 5         year = date.getFullYear(),
 6         month = date.getMonth(),
 7         day = date.getDate(),
 8         week = date.getDay(),
 9         currentDays = new Date(year, month + 1, 0).getDate(),
10         preDays = new Date(year, month, 0).getDate(),
11         firstDay = new Date(year, month, 1),
12         firstCell = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1,
13         bottomCell =  35 - currentDays - firstCell;
14     //前一个月该显示多少天
15     var preMonth = [];
16     for(var p = firstCell; p > 0; p--){
17         preMonth.push(new Date(year, month - 1, preDays - p + 1));
18     }
19     //本月
20     var currentMonth = [];
21     for(var c = 0; c < currentDays; c++){
22         currentMonth.push(new Date(year, month, c + 1));
23     }
24     //下一个月
25     var nextMonth = [];
26     for(var n = 0; n < bottomCell; n++){
27         nextMonth.push(new Date(year, month + 1, n + 1));
28     }
29 
30     preMonth = preMonth.concat(currentMonth, nextMonth);
31     return preMonth;
32 };
复制代码
(3)检测代码逻辑是否正确,正好在使用node cmd,所以索性在node下运行了(当如放到Chrome console也可以),不过需要先注释掉this.div = document.getElementById(div);这一行。var c = new Calendar();console.log(c.monthPanel(new Date(2014, 6, 1))); 其实不传递参数,就是显示当前月份的日历面板。如下图。
 
 
 
三、构建最基础的UI
 
(1)动态绘制35个表格
 
复制代码
 1     for(var i = 0; i < 35; i++){
 2         var cellDOM = document.createElement('div');
 3         cellDOM.style.width = cell.width + 'px';
 4         cellDOM.style.height = cell.height + 'px';
 5         cellDOM.style.display = 'inline-block';
 6         cellDOM.style.float = 'left';
 7         cellDOM.style.border = '1px solid blue';
 8         cellDOM.style.cursor = 'pointer';           this.div.appendChild(cellDOM);
11     }
复制代码
 
 
(2)显示日期和月份的头部
 
复制代码
 1 Calendar.prototype.showUI = function(date){
 2     var width = this.div.style.width || 800,
 3         height = this.div.style.height || (600 - 30),
 4         cell = {width: (parseInt(width) - 20)/7, height: (parseInt(height) -30 - 20)/5},
 5         monthArr = this.monthPanel(date);
 6 
 7     this.addHeader(date);
 8     for(var i = 0; i < 35; i++){
 9         var cellDOM = document.createElement('div');
10         cellDOM.style.width = cell.width + 'px';
11         cellDOM.style.height = cell.height + 'px';
12         cellDOM.style.display = 'inline-block';
13         cellDOM.style.float = 'left';
14         cellDOM.style.border = '1px solid blue';
15         cellDOM.style.cursor = 'pointer';
16         cellDOM.innerHTML = monthArr[i].getDate();
17         this.div.appendChild(cellDOM);
18     }
19     
20 };
21 
22 Calendar.prototype.addHeader = function(date){
23     var header = document.createElement('div');
24     header.style.height = '20px';
25     header.style.width = this.div.style.width || '800px';
26     header.style.textAlign = 'center';
27     header.style.fontWeight = 'bold';
28     header.innerHTML = date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
29     console.log(header);
30     this.div.appendChild(header);
31 }
复制代码
(3)编写HTML和整个逻辑代码
 
HTML:
 
复制代码
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <script type="text/javascript" src="calendar.js"></script>
        <script type="text/javascript">
            function showCalendar(){
                var c = new Calendar('calendar');
                c.showUI(new Date());
            }
        </script>
    </head>
    <body onload="showCalendar()">
        <div id="calendar" style="width:600px; height:400px;border:1px solid red;"></div>
    </body>
</html>
复制代码
javascript:
 
复制代码
 1 var Calendar = function(div){
 2     this.div = document.getElementById(div);
 3 };
 4 
 5 Calendar.week = ['星期一', '星期二','星期三', '星期四','星期五', '星期六', '星期日'];
 6 Calendar.month = ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'];
 7 
 8 Calendar.prototype.showUI = function(date){
 9     var width = this.div.style.width || 800,
10         height = this.div.style.height || (600 - 30),
11         cell = {width: (parseInt(width) - 20)/7, height: (parseInt(height) -30 - 20)/5},
12         monthArr = this.monthPanel(date);
13 
14     this.addHeader(date);
15     for(var i = 0; i < 35; i++){
16         var cellDOM = document.createElement('div');
17         cellDOM.style.width = cell.width + 'px';
18         cellDOM.style.height = cell.height + 'px';
19         cellDOM.style.display = 'inline-block';
20         cellDOM.style.float = 'left';
21         cellDOM.style.border = '1px solid blue';
22         cellDOM.style.cursor = 'pointer';
23         cellDOM.innerHTML = monthArr[i].getDate();
24         this.div.appendChild(cellDOM);
25     }
26     
27 };
28 
29 Calendar.prototype.addHeader = function(date){
30     var header = document.createElement('div');
31     header.style.height = '20px';
32     header.style.width = this.div.style.width || '800px';
33     header.style.textAlign = 'center';
34     header.style.fontWeight = 'bold';
35     header.innerHTML = date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
36     console.log(header);
37     this.div.appendChild(header);
38 }
39 
40 Calendar.prototype.monthPanel = function(date){
41     //如果传递了Date对象,则按Date对象进行计算月份面板
42     //否则,按照当前月份计算面板
43     var date = date || new Date(),
44         year = date.getFullYear(),
45         month = date.getMonth(),
46         day = date.getDate(),
47         week = date.getDay(),
48         currentDays = new Date(year, month + 1, 0).getDate(),
49         preDays = new Date(year, month, 0).getDate(),
50         firstDay = new Date(year, month, 1),
51         firstCell = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1,
52         bottomCell =  35 - currentDays - firstCell;
53     //前一个月该显示多少天
54     var preMonth = [];
55     for(var p = firstCell; p > 0; p--){
56         preMonth.push(new Date(year, month - 1, preDays - p + 1));
57     }
58     //本月
59     var currentMonth = [];
60     for(var c = 0; c < currentDays; c++){
61         currentMonth.push(new Date(year, month, c + 1));
62     }
63     //下一个月
64     var nextMonth = [];
65     for(var n = 0; n < bottomCell; n++){
66         nextMonth.push(new Date(year, month + 1, n + 1));
67     }
68 
69     preMonth = preMonth.concat(currentMonth, nextMonth);
70     return preMonth;
71 };
相关文章
最新文章
热点推荐