首页 > 代码库 > javascript动手写日历组件(3)——内存和性能优化(by vczero)

javascript动手写日历组件(3)——内存和性能优化(by vczero)

一、列表

javascript动手写日历组件的文章列表,主要是通过原生的JavaScript写的一个简约的日历组件:

(1)javascript动手写日历组件(1)——构建日历逻辑:http://www.cnblogs.com/vczero/p/js_ui_1.html

(2)javascript动手写日历组件(2)——优化UI和添加交互:http://www.cnblogs.com/vczero/p/js_ui_2.html

(3)javascript动手写日历组件(2)——内存和性能优化:http://www.cnblogs.com/vczero/p/js_ui_3.html

(4)github:https://github.com/vczero/UI

日历虽然很简约,但是作为基本使用可以满足要求,UI也相对清爽。

二、内存和性能优化

(1)手动移除事件处理程序

以为在DOM重绘的过程中,避免事件处理程序驻留内存,因此,手动XXX.onclik = null;

            for(var e = 0; e < 35; e++){                var node = document.getElementById(‘vczero_celldom_‘ + e);                node.onclick = null; //移除事件处理程序                this.div.removeChild(node);            }
        if(!!exist){            exist.onclick = null;            this.div.removeChild(exist);        }

(2)将绑定事件处理程序改成事件委托

对于事件处理程序过多的问题,使用委托是最好的方式。事件委托实际上是事件冒泡,可以在父节点添加事件处理程序,然后,根据需要的目标节点,执行代码。具体的代码改进如下,将for循环中的事件绑定改为在this.div(父元素)上的事件委托:

 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.id = ‘vczero_celldom_‘ + i;10             cellDOM.style.lineHeight = cell.height + ‘px‘;11             cellDOM.setAttribute(‘date‘,monthArr.date[i]); //设置日期对象到DOM属性date上12             cellDOM.innerHTML = monthArr.date[i].getDate();13             //去掉最后一行横线14             if(i < 28){15                 cellDOM.style.borderBottom = ‘1px solid #C8CACC‘;16             }17 18             if(i < monthArr.preLen || i >= monthArr.currentLen + monthArr.preLen){19                 cellDOM.style.color = ‘#BFBFBF‘;20             }21             this.div.appendChild(cellDOM);22         }23 24         var _that = this;26         //使用父元素事件委托27         this.div.addEventListener(‘click‘,function(e){28             var node = e.target;29             if(node.id.indexOf(‘vczero_celldom_‘) > -1){30                 var date = new Date(node.getAttribute(‘date‘)).toLocaleString();31                 callback(date);32             }33         });34             if(i < monthArr.preLen || i >= monthArr.currentLen + monthArr.preLen){35                 cellDOM.style.color = ‘#BFBFBF‘;36             }37             this.div.appendChild(cellDOM);38         }39 40         var _that = this;41         this.div.addEventListener(‘click‘,function(e){43             var node = e.target;44             if(node.id.indexOf(‘vczero_celldom_‘) > -1){45                 var date = new Date(node.getAttribute(‘date‘)).toLocaleString();46                 callback(date);47             }48         });

(3)本次修改还包括:

==>前一个月和下一个的日期变灰,本月黑色。

==>将,showUI函数改为回调,可以在调用时更为方便。

 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.showUI(function(date){10                     console.log(date);11                 });12             }13         </script>14     </head>15     <body onload="showCalendar()">16         <div id="calendar" style="width:390px; height:270px;"></div>17     </body>18 </html>

(4)整个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.showUI = function(callback){ 23         var exist = document.getElementById(‘vczero_celldom_0‘); 24         //如果存在节点:移除 25         if(!!exist){ 26             for(var e = 0; e < 35; e++){ 27                 var node = document.getElementById(‘vczero_celldom_‘ + e); 28                 node.onclick = null; //移除事件处理程序 29                 this.div.removeChild(node); 30             } 31         } 32  33         var width = this.width, 34             height = this.height, 35             cell = {width: (parseInt(width) - 20)/7, height: (parseInt(height) -30 - 20)/5}, 36             monthArr = this._monthPanel(this.date); 37         this.div.style.paddingLeft = ‘8px‘;  38         this.div.style.border = ‘2px solid #57ABFF‘; 39         this.div.style.cursor = ‘default‘; 40         this.div.style.fontFamily = ‘微软雅黑‘; 41         this._addHeader(); 42         this._addWeekday(); 43  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.date[i]); //设置日期对象到DOM属性date上 55             cellDOM.innerHTML = monthArr.date[i].getDate(); 56             //去掉最后一行横线 57             if(i < 28){ 58                 cellDOM.style.borderBottom = ‘1px solid #C8CACC‘; 59             } 60  61             if(i < monthArr.preLen || i >= monthArr.currentLen + monthArr.preLen){ 62                 cellDOM.style.color = ‘#BFBFBF‘; 63             } 64             this.div.appendChild(cellDOM); 65         } 66  67         var _that = this; 68         //使用父元素事件委托 69         this.div.addEventListener(‘click‘,function(e){ 70             var node = e.target; 71             if(node.id.indexOf(‘vczero_celldom_‘) > -1){ 72                 var date = new Date(node.getAttribute(‘date‘)).toLocaleString(); 73                 callback(date); 74             } 75         }); 76     }; 77  78     Calendar.prototype._addHeader = function(){ 79         var exist = document.getElementById(‘vczero_datediv‘); 80         if(!!exist){ 81             exist.onclick = null; 82             this.div.removeChild(exist); 83         } 84  85         var header = document.createElement(‘div‘); 86         header.style.height = ‘22px‘; 87         header.style.width = this.div.style.width || ‘800px‘; 88  89         //包含左 时间 右的大DIV 90         var dateDiv = document.createElement(‘div‘); 91         dateDiv.style.width = ‘200px‘; 92         dateDiv.style.height = ‘22px‘; 93         dateDiv.style.margin = ‘0 auto‘; 94         dateDiv.style.textAlign = ‘center‘; 95         dateDiv.style.fontWeight = ‘bold‘; 96         dateDiv.id = ‘vczero_datediv‘ 97  98         //< DIV 99         var leftDiv = document.createElement(‘div‘);100         leftDiv.innerHTML = ‘<‘;101         leftDiv.style.display = ‘inline-block‘;102         leftDiv.style.float = ‘left‘;103         leftDiv.style.width = ‘50px‘;104         leftDiv.style.cursor = ‘pointer‘;105         leftDiv.style.color = ‘#C5BFBF‘;106         var _that = this; //获取到this对象107         leftDiv.addEventListener(‘click‘, function(event){108             var year = parseInt(_that.date.getFullYear()),109                 month = parseInt(_that.date.getMonth());110             if(month === 0){111                 _that.date = new Date(year - 1, 11, 1);112             }else{113                 _that.date = new Date(year, month - 1, 1);114             }115             _that.showUI();116             117         });118 119         //> DIV120         var rightDiv = document.createElement(‘div‘);121         rightDiv.innerHTML = ‘>‘;122         rightDiv.style.display = ‘inline-block‘;123         rightDiv.style.float = ‘left‘;124         rightDiv.style.width = ‘50px‘;125         rightDiv.style.cursor = ‘pointer‘;126         rightDiv.style.color = ‘#C5BFBF‘;127         rightDiv.addEventListener(‘click‘, function(event){128             var year = parseInt(_that.date.getFullYear()),129                 month = parseInt(_that.date.getMonth());130             if(month === 11){131                 _that.date = new Date(year + 1, 0, 1);132             }else{133                 _that.date = new Date(year, month + 1, 1);134             }135             _that.showUI();136         });137 138 139         //显示月份的DIV140         var timeDiv = document.createElement(‘div‘);141         timeDiv.style.display = ‘inline-block‘;142         timeDiv.style.float = ‘left‘;143         timeDiv.style.width = ‘100px‘;144         timeDiv.innerHTML = this.date.getFullYear() + ‘年‘ + (this.date.getMonth() + 1) + ‘月‘;145 146         dateDiv.appendChild(leftDiv);147         dateDiv.appendChild(timeDiv);148         dateDiv.appendChild(rightDiv);149         this.div.appendChild(dateDiv);150     }151 152     //增加星期153     Calendar.prototype._addWeekday = function(){154         var exist = document.getElementById(‘vczero_week_0‘);155         if(!!exist){156             for(var i = 0; i < 7; i++){157                 var node = document.getElementById(‘vczero_week_‘ + i);158                 node.onclick = null;159                 this.div.removeChild(node);160             }161             162         }163 164         for(var i = 0; i < 7; i++){165             var weekday = document.createElement(‘div‘);166             weekday.style.width = (parseInt(this.width) - 20)/7 + ‘px‘;167             weekday.style.height = ‘20px‘;168             weekday.style.display = ‘inline-block‘;169             weekday.style.float = ‘left‘;170             weekday.style.color = ‘#BFBFBF‘;171             weekday.style.fontWeight = ‘bold‘;172             weekday.style.textAlign = ‘center‘;173             weekday.id = ‘vczero_week_‘ + i;174             weekday.innerHTML = Calendar.week[i];175             this.div.appendChild(weekday);176         }177     }178 179     Calendar.prototype._monthPanel = function(date){180         //如果传递了Date对象,则按Date对象进行计算月份面板181         //否则,按照当前月份计算面板182         var date = date || new Date(),183             year = date.getFullYear(),184             month = date.getMonth(),185             day = date.getDate(),186             week = date.getDay(),187             currentDays = new Date(year, month + 1, 0).getDate(),188             preDays = new Date(year, month, 0).getDate(),189             firstDay = new Date(year, month, 1),190             firstCell = firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1,191             bottomCell =  35 - currentDays - firstCell;192         //前一个月该显示多少天193         var preMonth = [];194         for(var p = firstCell; p > 0; p--){195             preMonth.push(new Date(year, month - 1, preDays - p + 1));196         }197         var len = preMonth.length;198         //本月199         var currentMonth = [];200         for(var c = 0; c < currentDays; c++){201             currentMonth.push(new Date(year, month, c + 1));202         }203         //下一个月204         var nextMonth = [];205         for(var n = 0; n < bottomCell; n++){206             nextMonth.push(new Date(year, month + 1, n + 1));207         }208 209         preMonth = preMonth.concat(currentMonth, nextMonth);210         return {211             date: preMonth,212             preLen: len,213             currentLen: currentMonth.length214         };215     };216 217     return Calendar;218 219 })();
View Code