首页 > 代码库 > 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 })();
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。