原生Js日历控件-多种状态可选

早就想自己写个日历控件练练手了,可惜一直没时间。

项目里一直都在用Jquery的日期控件,慢慢的需求增多了,不想改别人的,但是网站上放2个以上同功能的控件又不和谐,所以决定自己写一个。

照着淘宝的样式做了一个,目前实现了几种形态:

1.单月/双月的显示

2.年月是否可选

3.今日以前的日期是否可选

支持多个input 兼容ie/ff/chrome

原生Js日历控件-多种状态可选

在线预览地址:http://jsfiddle.net/dtdxrk/MA4x5/embedded/result/

压缩好的文件打包下载:http://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>

 

 

你可能感兴趣的:(日历控件)