早就想自己写个日历控件练练手了,可惜一直没时间。
项目里一直都在用Jquery的日期控件,慢慢的需求增多了,不想改别人的,但是网站上放2个以上同功能的控件又不和谐,所以决定自己写一个。
照着淘宝的样式做了一个,目前实现了几种形态:
1.单月/双月的显示
2.年月是否可选
3.今日以前的日期是否可选
支持多个input 兼容ie/ff/chrome
在线预览地址:http://jsfiddle.net/dtdxrk/MA4x5/embedded/result/
压缩好的文件打包下载:https://files.cnblogs.com/dtdxrk/Calendar.rar
1 <!DOCTYPE HTML> 2 <html lang="en"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title>原生Js日历控件-多种状态</title> 6 <style type="text/css"> 7 *{margin:0;padding: 0; } 8 9 #txt {background-color: green;padding: 5px;line-height: 1.5;color: #fff;} 10 11 /*日历控件*/ 12 input.input_Calendar, .div_Calendar button{ background: url(http://images.cnblogs.com/cnblogs_com/dtdxrk/485636/o_Calendar_bg.gif) no-repeat;} 13 14 .div_Calendar{display:none;z-index: 9999; overflow: hidden; font-size: 13px;padding:0 25px;_padding-bottom:15px;width:auto;box-shadow: 2px 2px 3px rgba(0,0,0,0.3);font-family: Arial; position: absolute;border:1px solid #ccc; background-color: #fff;} 15 .div_Calendar div.div_Month{margin:15px;float: left;_display:inline;} 16 .div_Calendar div.double{margin-left: 0;} 17 .div_Calendar div.div_Month h1{text-align: center;font-size: 13px;line-height: 1;margin-bottom: 5px;} 18 .div_Calendar div.div_Month table, .div_Calendar div.div_Month table th,.div_Calendar div.div_Month table td{border-collapse: collapse;} 19 .div_Calendar div.div_Month table{border-top:1px solid #DCDCDC;text-align: center;} 20 .div_Calendar div.div_Month table th{font-weight: normal;padding: 2px 5px;} 21 .div_Calendar div.div_Month table td{border:1px solid #DCDCDC;} 22 .div_Calendar div.div_Month table td span{padding: 2px 5px;color: #ccc; cursor:default ;display: block;} 23 .div_Calendar div.div_Month table td a{ text-decoration: none;color: #000; display: block;padding: 2px 5px;font-weight: bold;cursor: pointer;} 24 .div_Calendar div.div_Month table td a:hover{color: #fff;background-color: #5792dc; } 25 .div_Calendar div.div_Month table td a.active,.div_Calendar div.div_Month table td a.on{background-color:#5792dc;color: #fff;} 26 .div_Calendar button{position: absolute;padding: 5px 2px;border:0;cursor: pointer;text-indent: -9999px; } 27 .div_Calendar button.m_prev{left:10px;top:75px;width: 20px;height: 38px;} 28 .div_Calendar button.m_next{right: 10px;top:75px;background-position: -20px 0;width: 20px;height: 38px;} 29 .div_Calendar button.c_close{ right: 5px;top: 5px;width: 17px;height: 17px;background-position: -40px 0;} 30 31 input.input_Calendar{ 32 cursor: pointer; 33 border: 1px solid #ccc; 34 padding: 4px; 35 background-position: 95% -122px; 36 vertical-align: middle; 37 width: 100px; 38 } 39 40 </style> 41 42 <body> 43 <ul id="txt"> 44 <li>以前一直在用Jquery的日期控件,慢慢的需求增多了,修改别人的很头疼,但是网站上放2个以上同功能的控件又不和谐,所以决定自己写一个。 45 照着淘宝的样式做了一个,目前实现了几种形态:</li> 46 <li>1.单月/双月的显示</li> 47 <li>2.年月是否可选</li> 48 <li>3.今日以前的日期是否可选</li> 49 <li>4.兼容ie/ff/chrome</li> 50 </ul> 51 52 53 <div style="margin-top:200px;margin-left:400px;"> 54 入住时间<input type="text" class="input_Calendar" id="inDate" name="inDate" readOnly="true" value=""><br><br> 55 离店时间<input type="text" class="input_Calendar" id="outDate" name="outDate" readOnly="true" value=""> 56 <p> 57 <br> 58 <select name="IE6"> 59 <option>测试IE6</option> 60 <option>2</option> 61 <option>3</option> 62 </select> 63 <select name="IE6"> 64 <option>测试IE6</option> 65 <option>2</option> 66 <option>3</option> 67 </select> 68 <select name="IE6"> 69 <option>测试IE6</option> 70 <option>2</option> 71 <option>3</option> 72 </select> 73 <select name="IE6"> 74 <option>测试IE6</option> 75 <option>2</option> 76 <option>3</option> 77 </select> 78 <select name="IE6"> 79 <option>测试IE6</option> 80 <option>2</option> 81 <option>3</option> 82 </select> 83 <select name="IE6"> 84 <option>测试IE6</option> 85 <option>2</option> 86 <option>3</option> 87 </select></p> 88 </div> 89 90 其他时间<input type="text" class="input_Calendar" id="Date" name="Date" readOnly="true" value=""> 91 92 93 94 <script type="text/javascript"> 95 96 var _CalF = { 97 $ : function(object){//选择器 98 if(object === undefined ) return; 99 var getArr = function(name,tagName,attr){ 100 var tagName = tagName || '*', 101 eles = document.getElementsByTagName(tagName), 102 clas = (typeof document.body.style.maxHeight === "undefined") ? "className" : "class";//ie6 103 attr = attr || clas, 104 Arr = []; 105 for(var i=0;i<eles.length;i++){ 106 if(eles[i].getAttribute(attr)==name){ 107 Arr.push(eles[i]); 108 } 109 } 110 return Arr; 111 }; 112 113 if(object.indexOf('#') === 0){ //#id 114 return document.getElementById(object.substring(1)); 115 }else if(object.indexOf('.') === 0){ //.class 116 return getArr(object.substring(1)); 117 }else if(object.match(/=/g)){ //attr=name 118 return getArr(object.substring(object.search(/=/g)+1),null,object.substring(0,object.search(/=/g))); 119 }else if(object.match(/./g)){ //tagName.className 120 return getArr(object.split('.')[1],object.split('.')[0]); 121 } 122 }, 123 addHandler:function(node, type, handler){ 124 node.addEventListener ? node.addEventListener(type, handler, false) : node.attachEvent('on'+ type, handler); 125 }, 126 removeHandler: function (node, type, handler) { 127 node.removeEventListener ? node.removeEventListener(type, handler, false) : node.detachEvent("on" + type, handler); 128 }, 129 getPosition : function(obj) { //获取元素在页面里的位置和宽高 130 var top = 0, 131 left = 0, 132 width = obj.offsetWidth, 133 height = obj.offsetHeight; 134 135 while(obj.offsetParent){ 136 top += obj.offsetTop; 137 left += obj.offsetLeft; 138 obj = obj.offsetParent; 139 } 140 141 return {"top":top,"left":left,"width":width,"height":height}; 142 }, 143 addClass:function(c,node){ // 添加样式名 144 node.className = node.className + ' ' + c; 145 }, 146 removeClass:function(c,node){ // 移除样式名 147 var reg = new RegExp("(^|\\s+)" + c + "(\\s+|$)","g"); 148 node.className = node.className.replace(reg, ''); 149 }, 150 stopPropagation:function(event){ // 阻止冒泡 151 var event = event || window.event; 152 event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true; 153 }, 154 ie6 : function(){ 155 return !!window.ActiveXObject && !window.XMLHttpRequest; 156 } 157 158 }; 159 160 161 function Calender() { 162 this.init.apply(this, arguments); 163 } 164 165 Calender.prototype = { 166 _temp : [ //table数组模板 167 '<table>', 168 '<tr><th>日</th><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th></tr>' 169 ], 170 _tempButton :[ 171 '<button class="c_close" title="关闭" >关闭</button>', 172 '<button class="m_prev" title="上一月" >上一月</button>', 173 '<button class="m_next" title="下一月" >下一月</button>' 174 ], 175 init :function(options){ 176 this.id = options.id; //input id 177 this.input = _CalF.$("#"+this.id); //input 178 this.past = options.past; //以前的日期能不能选择 179 this.select = options.select; //日月选择 180 this.doubleMonths = options.doubleMonths; //显示两个月 181 this.createCalendar(); 182 this.inputEvent(); 183 }, 184 inputEvent : function(){ //input事件 185 var that = this; 186 _CalF.addHandler(this.input, 'click',function(){ 187 that.createMon(new Date()); 188 }); 189 }, 190 createCalendar : function(){//创建日历div并且定位 191 var div = this.CalendarDiv = document.createElement('div'), 192 input = _CalF.getPosition(this.input), 193 top = input.top, 194 left = input.left, 195 height = input.height; 196 divHtml = this._tempButton.concat(); //复制一个新数组 197 198 div.id = "Calendar_"+this.id; 199 div.className= "div_Calendar"; 200 div.innerHTML = divHtml.join(""); 201 div.style.top = (top+height) +"px"; 202 div.style.left = left +"px"; 203 _CalF.addHandler(div,"click", _CalF.stopPropagation); //阻止事件冒泡 204 document.body.appendChild(div); 205 this.btnEvent(); //按钮事件 206 }, 207 createIframe : function(){ //ie6创建iframe遮罩 208 var myIframe = document.createElement('iframe'); 209 myIframe.style.position = 'absolute'; 210 myIframe.style.zIndex = '-1'; 211 myIframe.style.left = '-1px'; 212 myIframe.style.top = 0; 213 myIframe.style.border = 0; 214 myIframe.style.filter = 'alpha(opacity= 0 )'; 215 myIframe.style.width = this.CalendarDiv.offsetWidth + 'px'; 216 myIframe.style.height = this.CalendarDiv.offsetHeight + 'px'; 217 return myIframe; 218 }, 219 del_Mon:function(){ //删除月节点 220 var that = this, 221 divs = that.CalendarDiv.getElementsByTagName("div"); 222 if(divs.length !== 0){ 223 that.CalendarDiv.removeChild(divs[0]); 224 if(this.doubleMonths)that.CalendarDiv.removeChild(divs[0]); 225 } 226 }, 227 createMon : function(idate){//创建div_Month 228 this.del_Mon(); 229 230 var now = new Date(), 231 now_year = now.getFullYear(), 232 now_month = now.getMonth(), 233 now_taday = now.getDate(), 234 i=1, //每月从1号开始 235 trs, //行数 236 h1, //h1 html 237 div_Month, //月div 238 year,month,date,time, 239 firstDay, //当月第一天星期几 240 ifTaday , 241 is_leap = function(year){return (year%400==0) ? 1 : 0},//是否为闰年 能够被400整除的闰年2月29天 不能被整除的是平年2月28天 242 months = [31,28+is_leap(this.year),31,30,31,31,30,31,30,31,30,31], //月天数 243 divHmtl = this._temp.concat(); //复制一个新数组 244 245 this.year = year = idate.getFullYear(); 246 this.month = month = idate.getMonth(); 247 this.date = date = idate.getDate(); 248 249 ifTaday = (year==now_year && month==now_month) ? true : false;//判断是不是今年今月 250 251 div_Month = document.createElement("div"); 252 div_Month.className = "div_Month"; 253 254 this.select ? h1 = this.isSelect(year,month) : h1 = "<h1>"+year+"年"+(month+1)+"月</h1>"; 255 256 firstDay = new Date(year,month,1).getDay(); 257 trs = Math.ceil((months[month]+firstDay)/7);//行数 258 259 for(var a =0;a<trs;a++){ 260 divHmtl.push("<tr>") 261 for(var b=0;b<7;b++){ 262 divHmtl.push("<td>"); 263 if (b >= firstDay) { 264 firstDay = 0; 265 if (i <= months[month]){ //循环当前月日期 266 if(ifTaday && i==now_taday){ 267 divHmtl.push("<a class='live active' date="+year+"-"+(month+1)+"-"+i+">"+i+"</a>") 268 }else if(this.past){ //今天以前的日期不可选 269 var old = new Date(this.year, this.month, i).getTime(), 270 taday = new Date(now_year, now_month, now_taday).getTime(); 271 (old<taday) ? divHmtl.push("<span>"+i+"</span>") : divHmtl.push("<a class='live' date="+year+"-"+(month+1)+"-"+i+">"+i+"</a>"); 272 }else{ 273 divHmtl.push("<a class='live' date="+year+"-"+(month+1)+"-"+i+">"+i+"</a>"); 274 } 275 i++; 276 } 277 } 278 divHmtl.push("</td>"); 279 } 280 divHmtl.push("</tr>") 281 } 282 283 divHmtl.unshift(h1); 284 div_Month.innerHTML = divHmtl.join(""); 285 this.CalendarDiv.appendChild(div_Month); 286 287 //显示两个月 288 if(this.doubleMonths) this.CalendarDiv.appendChild(this.creatdbMonths(idate)); 289 290 this.CalendarDiv.style.display = "block"; 291 292 this.aClick(); 293 this.outClick(); //body点击事件 294 if(this.select) this.selectChange(); //邦定事件 295 if(_CalF.ie6()){this.CalendarDiv.appendChild(this.createIframe())}; 296 }, 297 isSelect :function(year,month){ //返回select h1 298 var h1_html=[]; 299 h1_html.push('<h1><select id=yearSelect>'); 300 301 for(var y=2030;y>1941;y--){ 302 if(y==year){ 303 h1_html.push('<option value ="'+ y +'" selected>'+ y +'</option>'); 304 }else{ 305 h1_html.push('<option value ="'+ y +'">'+ y +'</option>'); 306 } 307 } 308 309 h1_html.push('</select>'); 310 h1_html.push(' 年 '); 311 h1_html.push('<select id=monthSelect>'); 312 313 for(var m=1;m<13;m++){ 314 if(m==(month+1)){ 315 h1_html.push('<option value ="'+ m +'" selected>'+ m +'</option>'); 316 }else{ 317 h1_html.push('<option value ="'+ m +'">'+ m +'</option>'); 318 } 319 } 320 321 h1_html.push('</select>'); 322 h1_html.push(' 月</h1>'); 323 324 return h1_html.join(""); 325 }, 326 creatdbMonths : function(idate){ 327 var now = new Date(), 328 now_year = now.getFullYear(), 329 now_month = now.getMonth(), 330 now_taday = now.getDate(), 331 i=1, //每月从1号开始 332 trs, //行数 333 h1, //h1 html 334 div_Month, //月div 335 year,month,date,time, 336 firstDay, //当月第一天星期几 337 ifTaday , // 338 is_leap = function(year){return (year%400==0) ? 1 : 0},//是否为闰年 能够被400整除的闰年2月29天 不能被整除的是平年2月28天 339 months = [31,28+is_leap(this.year),31,30,31,31,30,31,30,31,30,31], //月天数 340 divHmtl = this._temp.concat(); //复制一个新数组 341 342 year = idate.getFullYear(); 343 month = idate.getMonth()+1; 344 if(month>=12){ 345 month=0; 346 year+=1; 347 } 348 date = idate.getDate(); 349 350 ifTaday = (year==now_year && month==now_month) ? true : false;//判断是不是今年今月 351 352 div_Month = document.createElement("div"); 353 div_Month.className = "div_Month double"; 354 355 this.select ? h1 = this.isSelect(year,month) : h1 = "<h1>"+year+"年"+(month+1)+"月</h1>"; 356 357 firstDay = new Date(year,month,1).getDay(); 358 trs = Math.ceil((months[month]+firstDay)/7);//行数 359 360 for(var a =0;a<trs;a++){ 361 divHmtl.push("<tr>") 362 for(var b=0;b<7;b++){ 363 divHmtl.push("<td>"); 364 if (b >= firstDay) { 365 firstDay = 0; 366 if (i <= months[month]){ //循环当前月日期 367 if(ifTaday && i==now_taday){ 368 divHmtl.push("<a class='live active' date="+year+"-"+(month+1)+"-"+i+">"+i+"</a>") 369 }else if(this.past){ //今天以前的日期不可选 370 var old = new Date(year, month, i).getTime(), 371 taday = new Date(now_year, now_month, now_taday).getTime(); 372 (old<taday) ? divHmtl.push("<span>"+i+"</span>") : divHmtl.push("<a class='live' date="+year+"-"+(month+1)+"-"+i+">"+i+"</a>"); 373 }else{ 374 divHmtl.push("<a class='live' date="+year+"-"+(month+1)+"-"+i+">"+i+"</a>"); 375 } 376 i++; 377 } 378 } 379 divHmtl.push("</td>"); 380 } 381 divHmtl.push("</tr>") 382 } 383 384 divHmtl.unshift(h1); 385 div_Month.innerHTML = divHmtl.join(""); 386 return div_Month; 387 }, 388 selectChange : function(){ //select邦定事件 389 390 var that = this, 391 selects = that.CalendarDiv.getElementsByTagName("select"), 392 year,month, 393 yearSelect = selects[0], 394 monthSelect = selects[1]; 395 if(selects.length==4){ 396 var yearSelect2 = selects[2], 397 monthSelect2 = selects[3]; 398 _CalF.addHandler(yearSelect2, 'change',function(){ 399 year = yearSelect2.value; 400 month = monthSelect2.value; 401 that.createMon(new Date(year, month-1, that.date)); 402 }); 403 _CalF.addHandler(monthSelect2, 'change',function(){ 404 year = yearSelect2.value; 405 month = monthSelect2.value; 406 that.createMon(new Date(year, month-1, that.date)); 407 }); 408 } 409 410 _CalF.addHandler(yearSelect, 'change',function(){ 411 year = yearSelect.value; 412 month = monthSelect.value; 413 that.createMon(new Date(year, month-1, that.date)); 414 }); 415 _CalF.addHandler(monthSelect, 'change',function(){ 416 year = yearSelect.value; 417 month = monthSelect.value; 418 that.createMon(new Date(year, month-1, that.date)); 419 }); 420 }, 421 aClick : function(){ //a邦定事件 422 var that = this, 423 input = that.input, 424 links = _CalF.$("a.live"), 425 date,_temp=[]; 426 427 for(var i in links){ 428 links[i].onclick = function(){ 429 date = this.getAttribute("date"); 430 _temp = date.split("-"); 431 _temp[1] = (parseInt(_temp[1])<10) ? "0"+_temp[1] : _temp[1]; 432 _temp[2] = (parseInt(_temp[2])<10) ? "0"+_temp[2] : _temp[2]; 433 date = _temp.join("-"); 434 input.value = date; 435 that.removeCalender(); 436 }; 437 if(_CalF.ie6()){ 438 links[i].onmouseover = function(){ 439 _CalF.addClass("on",this); 440 }; 441 links[i].onmouseout = function(){ 442 _CalF.removeClass("on",this); 443 }; 444 } 445 } 446 }, 447 btnEvent:function(){ // 上一下一月年 按钮事件 448 var that = this, 449 bts = that.CalendarDiv.getElementsByTagName("button"); 450 bts[0].onclick = function(){ 451 that.removeCalender(); 452 }; 453 bts[1].onclick = function(){ 454 var idate = new Date(that.year, that.month-1, that.date); 455 that.createMon(idate); 456 }; 457 bts[2].onclick = function(){ 458 var idate = new Date(that.year, that.month+1, that.date); 459 that.createMon(idate); 460 }; 461 }, 462 removeCalender : function(){ //删除body点击事件 删除节点 463 this.CalendarDiv.style.display = "none"; 464 }, 465 outClick:function(){ // 鼠标在对象区域外点击,移除日期层 466 var that = this; 467 _CalF.addHandler(document.body, 'click',function(event){ 468 var event = event || window.event, 469 target = event.target || event.srcElement; 470 if(target == that.input || target==that.CalendarDiv) return; 471 that.removeCalender(); 472 }); 473 } 474 475 } 476 477 var input1 = new Calender({id:"inDate",past:true,select:true,doubleMonths:true}), 478 input2 = new Calender({id:"outDate",past:true,doubleMonths:true}), 479 input3 = new Calender({id:"Date",past:false,select:true}); 480 </script> 481 482 </body> 483 </html>