首页 > 代码库 > javascript动手写日历组件(2)——优化UI和添加交互(by vczero)

javascript动手写日历组件(2)——优化UI和添加交互(by vczero)

一、优化UI

继上一篇,http://www.cnblogs.com/vczero/p/js_ui_1.html。开始优化UI,主要优化的部分有:

(1)增加星期行。(2)字体设置。(3)日期垂直居中。(4)将单元格->底部线条。(5)修改文本的颜色对比。(6)将内部调用的函数加前缀_,如_addHeader()、_addWeekday()。

修改的后基本效果如下图:

整个代码做了小修小改:

 1 var Calendar = function(div){ 2     this.div = document.getElementById(div); 3     this.width = this.div.style.width || 800; //增加两变量 4     this.height = this.div.style.height || (600 - 30); 5 }; 6  7 Calendar.week = [‘星期一‘, ‘星期二‘,‘星期三‘, ‘星期四‘,‘星期五‘, ‘星期六‘, ‘星期日‘]; 8 Calendar.month = [‘1月‘,‘2月‘,‘3月‘,‘4月‘,‘5月‘,‘6月‘,‘7月‘,‘8月‘,‘9月‘,‘10月‘,‘11月‘,‘12月‘]; 9 10 Calendar.prototype.showUI = function(date){11     var width = this.width,12         height = this.height,13         cell = {width: (parseInt(width) - 20)/7, height: (parseInt(height) -30 - 20)/5},14         monthArr = this._monthPanel(date);15     this.div.style.paddingLeft = ‘8px‘; 16     this.div.style.border = ‘2px solid #57ABFF‘;17     this.div.style.cursor = ‘default‘;18     this.div.style.fontFamily = ‘微软雅黑‘;19     this._addHeader(date);20     this._addWeekday();21     for(var i = 0; i < 35; i++){22         var cellDOM = document.createElement(‘div‘);23         cellDOM.style.width = cell.width + ‘px‘;24         cellDOM.style.height = cell.height + ‘px‘;25         cellDOM.style.display = ‘inline-block‘;26         cellDOM.style.float = ‘left‘;27         cellDOM.style.cursor = ‘pointer‘;28         cellDOM.style.textAlign = ‘center‘;29         cellDOM.style.lineHeight = cell.height + ‘px‘;30         cellDOM.innerHTML = monthArr[i].getDate();31         //去掉最后一行横线32         if(i < 28){33             cellDOM.style.borderBottom = ‘1px solid #C8CACC‘;34         }35 36         this.div.appendChild(cellDOM);37     }38     39 };40 41 Calendar.prototype._addHeader = function(date){42     var header = document.createElement(‘div‘);43     header.style.height = ‘20px‘;44     header.style.width = this.div.style.width || ‘800px‘;45     header.style.textAlign = ‘center‘;46     header.style.fontWeight = ‘bold‘;47     header.innerHTML = date.getFullYear() + ‘年‘ + (date.getMonth() + 1) + ‘月‘;48     console.log(header);49     this.div.appendChild(header);50 }51 52 //增加星期53 Calendar.prototype._addWeekday = function(){54     for(var i = 0; i < 7; i++){55         var weekday = document.createElement(‘div‘);56         weekday.style.width = (parseInt(this.width) - 20)/7 + ‘px‘;57         weekday.style.height = ‘20px‘;58         weekday.style.display = ‘inline-block‘;59         weekday.style.float = ‘left‘;60         weekday.style.color = ‘#BFBFBF‘;61         weekday.style.fontWeight = ‘bold‘;62         weekday.innerHTML = Calendar.week[i];63         this.div.appendChild(weekday);64     }65 }66 67 Calendar.prototype._monthPanel = function(date){68     //如果传递了Date对象,则按Date对象进行计算月份面板69     //否则,按照当前月份计算面板70     var date = date || new Date(),71         year = date.getFullYear(),72         month = date.getMonth(),73         day = date.getDate(),74         week = date.getDay(),75         currentDays = new Date(year, month + 1, 0).getDate(),76         preDays = new Date(year, month, 0).getDate(),77         firstDay = new Date(year, month, 1),78         firstCell = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1,79         bottomCell =  35 - currentDays - firstCell;80     //前一个月该显示多少天81     var preMonth = [];82     for(var p = firstCell; p > 0; p--){83         preMonth.push(new Date(year, month - 1, preDays - p + 1));84     }85     //本月86     var currentMonth = [];87     for(var c = 0; c < currentDays; c++){88         currentMonth.push(new Date(year, month, c + 1));89     }90     //下一个月91     var nextMonth = [];92     for(var n = 0; n < bottomCell; n++){93         nextMonth.push(new Date(year, month + 1, n + 1));94     }95 96     preMonth = preMonth.concat(currentMonth, nextMonth);97     return preMonth;98 };

二、增加交互,选中返回日期对象

(1)点击日期,返回日期对象。

要想点击日期,返回日期对象,必须动态的添加事件。因此,需要在每个日期的DIV格子上添加事件,因此,会在创建cellDOM的时候添加事件监听。如下代码和图已经可以根据鼠标点击事件返回时间了。

 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.cursor = ‘pointer‘; 8         cellDOM.style.textAlign = ‘center‘; 9         cellDOM.style.lineHeight = cell.height + ‘px‘;10         cellDOM.setAttribute(‘date‘,monthArr[i]); //设置日期对象到DOM属性date上11         cellDOM.innerHTML = monthArr[i].getDate();12         //去掉最后一行横线13         if(i < 28){14             cellDOM.style.borderBottom = ‘1px solid #C8CACC‘;15         }16 17         cellDOM.addEventListener(‘click‘, function(event){18             console.log(this.getAttribute(‘date‘)); //通过this获取当前DOM的属性19         });20         this.div.appendChild(cellDOM);21     }

(2)封装事件,提供返回时间的接口

在Calendar的原型上定义个一个函数Calendar.prototype.getDate = null;暴露这个类函数,让开发者重写这个函数即可。

        <script type="text/javascript">            function showCalendar(){                var c = new Calendar(‘calendar‘);                c.getDate = function(event){                    alert(new Date(this.getAttribute(‘date‘)));                };                c.showUI(new Date());            }        </script>

(3)根据选择不同的月份,显示不同的日期面板

这时,就需要一个this.date对象,作为实例的属性,保证修改了this.date对象,其他原型函数也很获取到改变后的数值。下面最为重要的就是根据不同月份,重绘日历面板了。修改代码,增加向左,向右的月份控制。

向左(前一个月)的代码:

 1     var _that = this; //获取到this对象 2     leftDiv.addEventListener(‘click‘, function(event){ 3         var year = parseInt(_that.date.getFullYear()), 4             month = parseInt(_that.date.getMonth()); 5         if(month === 0){ 6             _that.date = new Date(year - 1, 11, 1); 7         }else{ 8             _that.date = new Date(year, month - 1, 1); 9         }10         _that.showUI();11         12     });

向右(下一个月)的代码控制:

 1 rightDiv.addEventListener(‘click‘, function(event){ 2         var year = parseInt(_that.date.getFullYear()), 3             month = parseInt(_that.date.getMonth()); 4         if(month === 11){ 5             _that.date = new Date(year + 1, 0, 1); 6         }else{ 7             _that.date = new Date(year, month + 1, 1); 8         } 9         _that.showUI();10     });

需要修改重绘的控制,以_addHeader()为例,判断DOM节点是否存在,如果存在移除DOM节点,重绘。

    var exist = document.getElementById(‘vczero_datediv‘);    if(!!exist){        this.div.removeChild(exist);    }

三、整个代码

整个简易日历已经可以使用了,上效果:

Calendar.js完整代码:

  1 /*  2 +------------------------------  3 @author:vczero  4 @time:2014/8/10  5 @desc:简易日历组件  6 +------------------------------  7 */  8 var Calendar = (function(){  9     var Calendar = function(div, date){ 10         this.div = document.getElementById(div); 11         var w = this.div.style.width || 390; 12         var h = this.div.style.height || (300 - 30); 13         this.width = parseInt(w) >= 360 ? w : 360;  14         this.height = parseInt(h) >= 180 ? h : 180; 15         this.date = date; 16         this.div.style.width = this.width + ‘px‘; //按默认值设置回去 17         this.div.style.height = this.height + ‘px‘;//按默认值设置回去 18     }; 19  20     Calendar.week = [‘星期一‘, ‘星期二‘,‘星期三‘, ‘星期四‘,‘星期五‘, ‘星期六‘, ‘星期日‘]; 21  22     Calendar.prototype.getDate = null; 23  24     Calendar.prototype.showUI = function(){ 25         var exist = document.getElementById(‘vczero_celldom_0‘); 26         //如果存在节点:移除 27         if(!!exist){ 28             for(var e = 0; e < 35; e++){ 29                 var node = document.getElementById(‘vczero_celldom_‘ + e); 30                 this.div.removeChild(node); 31             } 32         } 33  34         var width = this.width, 35             height = this.height, 36             cell = {width: (parseInt(width) - 20)/7, height: (parseInt(height) -30 - 20)/5}, 37             monthArr = this._monthPanel(this.date); 38         this.div.style.paddingLeft = ‘8px‘;  39         this.div.style.border = ‘2px solid #57ABFF‘; 40         this.div.style.cursor = ‘default‘; 41         this.div.style.fontFamily = ‘微软雅黑‘; 42         this._addHeader(); 43         this._addWeekday(); 44         for(var i = 0; i < 35; i++){ 45             var cellDOM = document.createElement(‘div‘); 46             cellDOM.style.width = cell.width + ‘px‘; 47             cellDOM.style.height = cell.height + ‘px‘; 48             cellDOM.style.display = ‘inline-block‘; 49             cellDOM.style.float = ‘left‘; 50             cellDOM.style.cursor = ‘pointer‘; 51             cellDOM.style.textAlign = ‘center‘; 52             cellDOM.id = ‘vczero_celldom_‘ + i; 53             cellDOM.style.lineHeight = cell.height + ‘px‘; 54             cellDOM.setAttribute(‘date‘,monthArr[i]); //设置日期对象到DOM属性date上 55             cellDOM.innerHTML = monthArr[i].getDate(); 56             //去掉最后一行横线 57             if(i < 28){ 58                 cellDOM.style.borderBottom = ‘1px solid #C8CACC‘; 59             } 60              61             cellDOM.addEventListener(‘click‘, this.getDate); 62             this.div.appendChild(cellDOM); 63         } 64          65     }; 66  67  68     Calendar.prototype._addHeader = function(){ 69         var exist = document.getElementById(‘vczero_datediv‘); 70         if(!!exist){ 71             this.div.removeChild(exist); 72         } 73  74         var header = document.createElement(‘div‘); 75         header.style.height = ‘22px‘; 76         header.style.width = this.div.style.width || ‘800px‘; 77  78         //包含左 时间 右的大DIV 79         var dateDiv = document.createElement(‘div‘); 80         dateDiv.style.width = ‘200px‘; 81         dateDiv.style.height = ‘22px‘; 82         dateDiv.style.margin = ‘0 auto‘; 83         dateDiv.style.textAlign = ‘center‘; 84         dateDiv.style.fontWeight = ‘bold‘; 85         dateDiv.id = ‘vczero_datediv‘ 86  87         //< DIV 88         var leftDiv = document.createElement(‘div‘); 89         leftDiv.innerHTML = ‘<‘; 90         leftDiv.style.display = ‘inline-block‘; 91         leftDiv.style.float = ‘left‘; 92         leftDiv.style.width = ‘50px‘; 93         leftDiv.style.cursor = ‘pointer‘; 94         leftDiv.style.color = ‘#C5BFBF‘; 95         var _that = this; //获取到this对象 96         leftDiv.addEventListener(‘click‘, function(event){ 97             var year = parseInt(_that.date.getFullYear()), 98                 month = parseInt(_that.date.getMonth()); 99             if(month === 0){100                 _that.date = new Date(year - 1, 11, 1);101             }else{102                 _that.date = new Date(year, month - 1, 1);103             }104             _that.showUI();105             106         });107 108         //> DIV109         var rightDiv = document.createElement(‘div‘);110         rightDiv.innerHTML = ‘>‘;111         rightDiv.style.display = ‘inline-block‘;112         rightDiv.style.float = ‘left‘;113         rightDiv.style.width = ‘50px‘;114         rightDiv.style.cursor = ‘pointer‘;115         rightDiv.style.color = ‘#C5BFBF‘;116         rightDiv.addEventListener(‘click‘, function(event){117             var year = parseInt(_that.date.getFullYear()),118                 month = parseInt(_that.date.getMonth());119             if(month === 11){120                 _that.date = new Date(year + 1, 0, 1);121             }else{122                 _that.date = new Date(year, month + 1, 1);123             }124             _that.showUI();125         });126 127 128         //显示月份的DIV129         var timeDiv = document.createElement(‘div‘);130         timeDiv.style.display = ‘inline-block‘;131         timeDiv.style.float = ‘left‘;132         timeDiv.style.width = ‘100px‘;133         timeDiv.innerHTML = this.date.getFullYear() + ‘年‘ + (this.date.getMonth() + 1) + ‘月‘;134 135         dateDiv.appendChild(leftDiv);136         dateDiv.appendChild(timeDiv);137         dateDiv.appendChild(rightDiv);138 139         this.div.appendChild(dateDiv);140     }141 142     //增加星期143     Calendar.prototype._addWeekday = function(){144         var exist = document.getElementById(‘vczero_week_0‘);145         if(!!exist){146             for(var i = 0; i < 7; i++){147                 var node = document.getElementById(‘vczero_week_‘ + i);148                 this.div.removeChild(node);149             }150             151         }152 153         for(var i = 0; i < 7; i++){154             var weekday = document.createElement(‘div‘);155             weekday.style.width = (parseInt(this.width) - 20)/7 + ‘px‘;156             weekday.style.height = ‘20px‘;157             weekday.style.display = ‘inline-block‘;158             weekday.style.float = ‘left‘;159             weekday.style.color = ‘#BFBFBF‘;160             weekday.style.fontWeight = ‘bold‘;161             weekday.style.textAlign = ‘center‘;162             weekday.id = ‘vczero_week_‘ + i;163             weekday.innerHTML = Calendar.week[i];164             this.div.appendChild(weekday);165         }166     }167 168     Calendar.prototype._monthPanel = function(date){169         //如果传递了Date对象,则按Date对象进行计算月份面板170         //否则,按照当前月份计算面板171         var date = date || new Date(),172             year = date.getFullYear(),173             month = date.getMonth(),174             day = date.getDate(),175             week = date.getDay(),176             currentDays = new Date(year, month + 1, 0).getDate(),177             preDays = new Date(year, month, 0).getDate(),178             firstDay = new Date(year, month, 1),179             firstCell = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1,180             bottomCell =  35 - currentDays - firstCell;181         //前一个月该显示多少天182         var preMonth = [];183         for(var p = firstCell; p > 0; p--){184             preMonth.push(new Date(year, month - 1, preDays - p + 1));185         }186         //本月187         var currentMonth = [];188         for(var c = 0; c < currentDays; c++){189             currentMonth.push(new Date(year, month, c + 1));190         }191         //下一个月192         var nextMonth = [];193         for(var n = 0; n < bottomCell; n++){194             nextMonth.push(new Date(year, month + 1, n + 1));195         }196 197         preMonth = preMonth.concat(currentMonth, nextMonth);198         return preMonth;199     };200 201     return Calendar;202 203 })();

测试的HTML代码:

 1 <!doctype html> 2 <html> 3     <head> 4         <meta charset="utf-8" /> 5         <script type="text/javascript" src="calendar.js"></script> 6         <script type="text/javascript"> 7             function showCalendar(){ 8                 var c = new Calendar(calendar,new Date()); 9                 c.getDate = function(event){10                     alert(new Date(this.getAttribute(date)).toLocaleString());11                 };12                 c.showUI();13             }14         </script>15     </head>16     <body onload="showCalendar()">17         <div id="calendar" style="width:390px; height:270px;"></div>18     </body>19 </html>

github:https://github.com/vczero/myUI

下一篇:修复bug和兼容性测试。