2020-11-11

原生JavaScript实现一种日历

设计目标:不依赖其他库、兼容一些旧版浏览器、可配置可扩展。

测试页面:

 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4  <meta charset="UTF-8"> 5  <title>测试日历控件</title> 6  <style> 7   #div1{ 8    width: 256px; 9    height: 202px; 10    box-sizing: border-box; 11    background-color: #fff; 12    box-shadow: 1px 1px 3px #999; 13    position:absolute; 14    left:0px; 15   } 16   #div2 { 17    width: 236px; 18    height: 166px; 19    box-sizing: border-box; 20    background-color: #fff; 21    box-shadow: 1px 1px 3px #999; 22    position:absolute; 23    left:300px; 24   } 25   .select_date{ 26    padding-left: 10px;box-sizing:border-box;width: 100px;height: 30px;background-color: #fff;font-size: 12px;float: left;line-height: 30px; 27   } 28   .span_rq{ 29    width: 60px;display: inline-block; 30   } 31  </style> 32  <script src="DatePicker.js"></script> 33 </head> 34 <body> 35 <div id="div_all_base" style="background-color: beige"> 36  <div id="div1"> 37  38  </div> 39  <div id="div2"> 40  41  </div> 42  <div style="width: 600px;height: 30px;left:600px;position:absolute;float:left" id="div3"> 43   <div style="float: left;line-height: 30px;margin-left: 10px;font-size: 12px;">从</div> 44   <div class="select_date"><span class="span_rq">开始日期</span><img src="image/rili2.jpg" style="margin-left: 10px;width: 20px;margin-top: 6px;cursor: pointer" alt="" onclick="var divs=div_rilis.getElementsByClassName('div_rili');divs[0].style.display='block';divs[1].style.display='none'"></div> 45   <div style="position: absolute;width:256px;height: 202px;top:50px;display: none" class="div_rili"></div> 46   <div style="float: left;line-height: 30px;margin-left: 10px;font-size: 12px;">到</div> 47   <div class="select_date"><span class="span_rq">结束日期</span><img src="image/rili2.jpg" style="margin-left: 10px;width: 20px;margin-top: 6px;cursor: pointer" alt="" onclick="var divs=div_rilis.getElementsByClassName('div_rili');divs[1].style.display='block';divs[0].style.display='none'"></div> 48   <div style="position: absolute;width:256px;height: 202px;top:50px;left:120px;display: none" class="div_rili"></div> 49  </div> 50 </div> 51 </body> 52 <script> 53  var div_rilis=document.getElementById("div3"); 54  55  var apiHost=""; 56  var data_enabledate={list_enabledate:[{CBRQ:20201111},{CBRQ:20201112},{CBRQ:20201113},{CBRQ:20201114},{CBRQ:20201115}],type:"ok"}; 57  //用AJAX从后端查询可选日期,需要返回数据的格式与data_enabledate相同 58  //var datepicker1=new DatePicker("datepicker1",{pickcallback:loadPage,bannerBackColor:"rgb(0,112,192)",searchEnableUrl:apiHost+"/public/searchEnableDate"});// 59  //直接用前端数据,设置了点击回调、banner颜色、激活日期 60  var datepicker1=new DatePicker("datepicker1",{pickcallback:loadPage,bannerBackColor:"rgb(0,112,192)",searchEnableUrl:data_enabledate}); 61  var div_rili1=document.getElementById("div1"); 62  div_rili1.appendChild(datepicker1.div); 63  datepicker1.reloadDateList(); 64  65  //设置更多的配置项,被点击的按钮变色,程序可以在一定的范围内根据外围div的大小调整每个按钮的尺寸,另外设置了字体大小,以及允许点击未激活日期 66  var datepicker2=new DatePicker("datepicker2",{ 67   pickcallback:function(str_date,that){ 68    datepicker2.pick0(str_date); 69    loadPage(str_date); 70   },bannerBackColor:"rgb(0,112,192)",width:236,height:166,shadowSize:0,paddingSize:0, 71   searchEnableUrl:data_enabledate,contentFontSize:9,flag_canPickUnEnabled:true, 72  }); 73  var div_rili2=document.getElementById("div2"); 74  div_rili2.appendChild(datepicker2.div); 75  datepicker2.reloadDateList(); 76  77  function loadPage(str_date){ 78  79   alert("点击的日期是"+str_date); 80  } 81  82  //常用的起始日期和结束日期,这里设置了每个日历的title,不区分激活按钮,并且把日历的值与span的innerHTML关联起来(使用arr_valuelink属性可以关联input或textview的value) 83  var divs=div_rilis.getElementsByClassName('div_rili'); 84  var spans=div_rilis.getElementsByClassName("span_rq"); 85  var datepicker1b=new DatePicker("datepicker1b",{pickcallback:function(value,that){ 86    var divs=div_rilis.getElementsByClassName('div_rili'); 87    divs[0].style.display='none'; 88    divs[1].style.display='none'; 89    DatePicker.linkValue(value,that) 90   },bannerBackColor:"rgb(0,112,192)",arr_innerlink:[spans[0]],title:"开始日期"});//与react不同这里的spans在onload后不会再重新生成,所以可以直接关联dom对象!! 91  var datepicker2b=new DatePicker("datepicker2b",{pickcallback:function(value,that){ 92    var divs=div_rilis.getElementsByClassName('div_rili'); 93    divs[0].style.display='none'; 94    divs[1].style.display='none'; 95    DatePicker.linkValue(value,that) 96   },bannerBackColor:"rgb(0,112,192)",arr_innerlink:[spans[1]],title:"结束日期"}); 97  divs[0].appendChild(datepicker1b.div); 98  divs[1].appendChild(datepicker2b.div); 99  datepicker1b.reloadDateList();100  datepicker2b.reloadDateList();101 </script>102 </html>

日历按钮图片:

代码实现:(建议从后往前看)

 1 DatePicker=function(id,obj_p) 2 { 3  //如果已经有这个div则建立失败 4  var div=document.getElementById("id"); 5  if(div) 6  { 7   console.log("组件id重复,请使用其他组件id"); 8   return; 9  } 10  div=document.createElement("div");//最外层容器 11  this.id=id; 12  this.div=div; 13  div.id=id; 14  var _this=this; 15  16  this.width=obj_p.width||256; 17  this.height=obj_p.height||202; 18  this.shadowSize=obj_p.shadowSize||4; 19  this.shadowColor=obj_p.shadowColor||"rgb(203,203,203)"; 20  this.backColor=obj_p.backColor||"white"; 21  //this.boxShadow=obj_p.boxShadow||"inset 0 0 4px 4px rgb(203,203,203)"; 22  div.style.border="0px"; 23  div.style.width=this.width+"px"; 24  div.style.height=this.height+"px"; 25  div.style.boxShadow="inset 0 0 "+this.shadowSize+"px "+this.shadowSize+"px "+this.shadowColor; 26  div.style.position="absolute"; 27  div.style.backgroundColor=this.backColor; 28  29  this.title=obj_p.title||"日期选择"; 30  //this.noTitle=obj.noTitle||false; 31  //this.noBanner=obj.noBanner||false; 32  this.h1=obj_p.h1||24;//最上面的一行空间 33  this.h2=obj_p.h2||24; 34  //this.h3=obj_p.h3||208; 35  this.titleFontSize=obj_p.titleFontSize||12; 36  this.contentFontSize=obj_p.contentFontSize||10; 37  var span=document.createElement("span")//日历的标题栏 38  span.innerText=this.title; 39  span.style.height=this.h1+"px"; 40  span.style.fontSize=this.titleFontSize+"px"; 41  span.style.fontWeight="bold"; 42  span.style.lineHeight=this.h1+"px"; 43  span.style.display="inline-block"; 44  span.style.left=this.shadowSize+"px"; 45  span.style.paddingLeft=this.shadowSize+"px"; 46  span.style.position="absolute"; 47  span.style.zIndex="2"; 48  div.appendChild(span); 49  50  this.bannerBackColor=obj_p.bannerBackColor||"rgb(169,16,10)"; 51  this.bannerFontColor=obj_p.bannerFontColor||"white"; 52  this.date=obj_p.date||(new Date());//默认日期 53  this.year=this.date.getFullYear(); 54  this.month=this.date.getMonth(); 55  this.day31=this.date.getDate(); 56  this.day7=this.date.getDay(); 57  this.arr_day7=obj_p.arr_day7||["","一","二","三","四","五","六","日"]; 58  this.arr_bannerp=obj_p.arr_bannerp||([//用来调整年月的按钮 59   {id:"btn1",width:10,marginLeft:20,text:"《",onclick:function(){_this.year-=10;_this.changeYear()}} 60   ,{id:"btn2",width:10,marginLeft:5,text:"〈",onclick:function(){_this.year-=1;_this.changeYear()}} 61   ,{id:"btn3",width:40,marginLeft:5,text:this.year,onclick:function(){}} 62   ,{id:"btn4",width:10,marginLeft:5,text:"〉",onclick:function(){_this.year+=1;_this.changeYear()}} 63   ,{id:"btn5",width:10,marginLeft:5,text:"》",onclick:function(){_this.year+=10;_this.changeYear()}} 64   ,{id:"btn6",width:10,marginLeft:50,text:"〈",onclick:function(){_this.month-=1;if(_this.month<0){_this.month=11;_this.year-=1;}_this.changeMonth();_this.changeYear()}} 65   ,{id:"btn7",width:20,marginLeft:5,text:this.month+1,onclick:function(){}} 66   ,{id:"btn8",width:10,marginLeft:5,text:"〉",onclick:function(){_this.month+=1;if(_this.month>11){_this.month=0;_this.year+=1;}_this.changeMonth();_this.changeYear()}} 67   ]) 68  69  var div_banner=document.createElement("div"); 70  div_banner.style.height=this.h2+"px"; 71  //div_banner.style.width="100%"; 72  div_banner.style.left=this.shadowSize+"px"; 73  div_banner.style.right=this.shadowSize+"px"; 74  div_banner.style.top=this.h1+"px"; 75  div_banner.style.position="absolute"; 76  div_banner.style.backgroundColor=this.bannerBackColor; 77  div_banner.style.lineHeight=this.h2+"px"; 78  div_banner.style.zIndex="2"; 79  //div_banner.style.fontSize=this.contentFontSize+2+"px"; 80  //div_banner.style.color=this.bannerFontColor; 81  //div_banner.style.fontWeight="bold"; 82  83  //this.changeYearBack=obj_p. 84  85  var len=this.arr_bannerp.length; 86  var sum_left=0; 87  for(var i=0;i<len;i++)//banner上调整年月的按钮 88  { 89   var bannerp=this.arr_bannerp[i]; 90   var btn=document.createElement("button"); 91   btn.id=bannerp.id; 92   btn.style.position="absolute"; 93   btn.style.backgroundColor=this.bannerBackColor; 94   btn.style.border="0px"; 95   btn.style.padding="0px"; 96   btn.style.textAlign="center"; 97   btn.style.color=this.bannerFontColor;//button这个属性并不会自动继承 98   btn.style.fontWeight="bold"; 99   btn.style.fontSize=this.contentFontSize+2+"px";100   btn.style.height="100%";101   btn.style.lineHeight=this.h2+"px";102   btn.style.width=bannerp.width+"px";103   btn.style.left=sum_left+bannerp.marginLeft+"px";104   btn.innerText=bannerp.text;105   btn.onclick=bannerp.onclick;106   sum_left+=(bannerp.width+bannerp.marginLeft);107   this[btn.id]=btn;108   div_banner.appendChild(btn);109  }110  div.appendChild(div_banner);111  this.paddingSize=obj_p.paddingSize||6;112 113  this.gridBackColor=obj_p.gridBackColor||"#eeeeee";//单元格背景颜色114  this.gridColor=obj_p.gridColor||"#000000";//本月单元格的文字颜色115  this.gridColor0=obj_p.gridColor0||"#888888";//连带显示的非本月单元格的文字颜色116  this.hoverBorderColor=obj_p.hoverBorderColor||"#888888";//鼠标移入可选单元格后的边框颜色117  this.enableBackColor=obj_p.enableBackColor||"rgb(207,232,252)";//可以被选择的单元格的背景颜色118  this.enableBackColorPicked=obj_p.enableBackColorPicked||"rgb(252,232,207)";119  var div_list=document.createElement("div");//按钮容器120  var int1=this.shadowSize+this.paddingSize;121  div_list.style.left=int1+"px";122  div_list.style.right=int1+"px";123  div_list.style.top=int1+"px";124  div_list.style.bottom=this.shadowSize+"px";125  div_list.style.position="absolute";126  div_list.style.backgroundColor=this.gridBackColor;127  div.appendChild(div_list);128  this.sizex=Math.floor((this.width-int1*2)/7);//按钮尺寸129  this.sizey=Math.floor((this.height-int1-this.shadowSize-(this.h1+this.h2-this.shadowSize-this.paddingSize))/7);130  this.pickcallback=obj_p.pickcallback;//鼠标点击日期按钮之后的响应方法131  this.div_list=div_list;132  this.obj_enable={};133  this.searchEnableUrl=obj_p.searchEnableUrl;//||apiHost+"/public/searchEnableDate";134  this.flag_canPickUnEnabled=obj_p.flag_canPickUnEnabled||false;//是否可以点击不激活的按钮135  if(!this.searchEnableUrl)//根本不区分按钮是否激活136  {137   this.flag_canPickUnEnabled=true;138  }139  //this.reloadDateList(obj_p.initcallback);140  //将日历的选择值与某些dom对象关联起来141  this.arr_innerlink=obj_p.arr_innerlink||[];142  this.arr_valuelink=obj_p.arr_valuelink||[];143 }144 DatePicker.linkValue=function(value,that)//改变与日历相关联的dom对象的值145 {146  var len=that.arr_innerlink.length;147  for(var i=0;i<len;i++)148  {149   that.arr_innerlink[i].innerHTML=value;150  }151  var len=that.arr_valuelink.length;152  for(var i=0;i<len;i++)153  {154   that.arr_valuelink[i].value=value;155  }156 }157 DatePicker.prototype.changeYear=function()158 {159  this.btn3.innerText=this.year;160  this.reloadDateList();//根据当前月份重新排列日期btn161  console.log("改变了年份")162 }163 DatePicker.prototype.changeMonth=function()164 {165  this.btn7.innerText=this.month+1;166  console.log("改变了月份")167 }168 DatePicker.DrawButton=function(that,callback)169 {//重新渲染选中月份的日历按钮170  try {171 172   var sizex = that.sizex;//每个小块的宽度173   var sizey = that.sizey;//每个小块的宽度174   var date_list = new Date(that.year + "-" + (that.month + 1) + "-1");//取这个月的第一天175   var day7_list = date_list.getDay();//是周几176   //上一个月有几天?177   var date_list0 = date_list - 1000 * 60 * 60;//上个月的最后一天178   var day31_list0 = (new Date(date_list0)).getDate();//是几号179 180   var int3 = that.month + 2;181   var int4 = that.year;182   if (int3 > 12) {183    int3 = 1;184    int4++;185   }186   var date_list2 = new Date(int4 + "-" + (int3) + "-1");//取下个月的第一天187   var date_list1 = date_list2 - 1000 * 60 * 60;//这个月的最后一天188   var day31_list1 = (new Date(date_list1)).getDate();//是几号189   for (var i = 0; i < (day7_list - 1); i++) {//补齐日历第一行的灰色部分190    that.arr_date.push({text: day31_list0 - (day7_list - 2 - i), inmonth: false})191   }192   if(that.searchEnableUrl)//如果要区分按钮是否激活193   {194    var list_enabledate = that.obj_json.list_enabledate;195    for (var i = 1; i <= day31_list1; i++) {196     var len = list_enabledate.length;197     var str_fulldate = that.year + (that.month + 1 + 100 + "").substr(1) + (i + 100 + "").substr(1);198     var obj = {text: i, inmonth: true, isenable: false, str_fulldate: str_fulldate};199     for (var j = 0; j < len; j++) {200      if (list_enabledate[j].CBRQ == (str_fulldate)) {201       obj.isenable = true;202       //obj.str_fulldate=str_fulldate;203       break;204      }205     }206     that.arr_date.push(obj);207    }208   }209   else {210    for (var i = 1; i <= day31_list1; i++) {211     var str_fulldate = that.year + (that.month + 1 + 100 + "").substr(1) + (i + 100 + "").substr(1);212     var obj = {text: i, inmonth: true, isenable: false, str_fulldate: str_fulldate};213     //obj.isenable = true;<-在不区分是否激活的情况下,不需要变色标记214     that.arr_date.push(obj);215    }216   }//将本月内的日期对象推入217 218   var len = that.arr_date.length;219   for (i = 0; i < (42 - len); i++) {//补上本月剩余的灰色部分220    that.arr_date.push({text: i + 1, inmonth: false})221   }222       //开始绘制按钮223   var int2 = that.h1 + that.h2 - that.shadowSize - that.paddingSize;224   for (var i = 0; i < 7; i++)//对于每一行225   {226    for (var j = 0; j < 7; j++) {227 228     (function () {//这里需要用闭包避免var变量污染229      var div = document.createElement("div");230      div.class = "div_riligrid";231      //div.className="div_riligrid";232      div.style.position = "absolute";233      div.style.display = "inline-block";234      div.style.top = i * sizey + int2 + "px";235      div.style.left = j * sizex + "px";236      div.style.width = sizex + "px";237      div.style.height = sizey + "px";238 239      //div.style.borderWidth="0px"240      //div.style.borderColor=that.hoverBorderColor241      div.style.textAlign = "center";242 243 244      if (i == 0)//第一行显示一周七天的名字,按中式习惯从周一到周日显示245      {246       div.style.color = that.gridColor;247       div.innerText = that.arr_day7[j + 1];248       div.style.fontSize = that.contentFontSize + "px";249       div.style.cursor = "default";250      }251      else//接下来根据列表生成日期小块252      {253       div.style.fontSize = that.contentFontSize + 4 + "px";254       div.style.cursor = "pointer";255       var index = (i - 1) * 7 + j;256       (function () {257        var obj = that.arr_date[index];258        div.innerText = obj.text;259        if (!obj.inmonth) {//对于不在本月内的占位按钮260         div.style.color = that.gridColor0;261        }262        else//根据条件判断按钮是否可点击263        {264         div.style.color = that.gridColor;265         //obj.isEnabled=false;266         //div.style.borderWidth267         /*div.onclick=function(){268          that.pickcallback(obj.text)269         }*/270         div.style.top = i * sizey + int2 + 1 + "px";271         div.style.left = j * sizex + 1 + "px";272         div.style.width = sizex - 2 + "px";273         div.style.height = sizey - 2 + "px";274         if (obj.isenable == true || that.flag_canPickUnEnabled) {275          div.onclick = function () {276           //obj.isenable277           that.pickcallback(obj.str_fulldate,that)278          }279         }280 281         //div.style.border="1px solid "+that.hoverBorderColor;282         //鼠标移入移出事件283         div.onpointerenter = function () {//鼠标移入时显示边框284          div.style.border = "1px solid " + that.hoverBorderColor;285         }286         div.onpointerleave = function () {287          div.style.border = "0px"288         }289         that.obj_enable["div_" + obj.str_fulldate] = div;290         if (obj.isenable) {291          div.style.backgroundColor = that.enableBackColor;292 293         }294        }295       })()296       //事件297      }298      that.div_list.appendChild(div);299     })()300    }301   }302   that.inited=true;303   if (that.true_cbrq) {304     that.pick(that.true_cbrq);305   }306   if (callback) {307    callback();308   }309  }catch(e)310  {311   alert(e);312   console.log(e);313  }314 }315 DatePicker.prototype.reloadDateList=function(callback)316 {//重新渲染当前月份日历按钮前,从后台查询本月激活按钮317  console.log("重新加载日期列表")//7*6标准318  this.arr_date=[];319  this.obj_enable={};320  this.div_list.innerHTML="";321  var that=this;322  //有可能不需要后台查询!323  if(this.searchEnableUrl)324  {325   if(typeof searchEnableUrl=="string") {//如果url是字符串326 327 328    //先绘制标签还是先查询标签限制?329    var ajax = create330    ajax.open("POST", this.searchEnableUrl);331    ajax.onreadystatechange = function () {//这里取到的this时ajax对象!332     if (ajax.readyState == 4) {333 334      if (ajax.status == 200) {335       var str_json = ajax.responseText;336       try {337        var obj_json = JSON.parse(str_json);338        if (obj_json.type == "ok") {339         that.obj_json = obj_json;340         DatePicker.DrawButton(that, callback);341 342        }343        else if (obj_json.type == "error") {344         alert(obj_json.str_res);345         console.log(obj_json.str_res);346        }347       }348       catch (e) {349        alert(e);350        console.log(e);351       }352       ajax.abort();353      }354     }355    }356 357    //var obj_json={ str_month:this.year+(this.month+1+100+"").substr(1)}358    //ajax.send(JSON.stringify(obj_json));//总之sb2的servlet不能自动转化json和FormData359    var formData = new FormData()360    formData.append("str_month", this.year + (this.month + 1 + 100 + "").substr(1));361    ajax.send(formData);362    //363   }364   else {365    that.obj_json = this.searchEnableUrl;//不去后端查询,直接把searchEnableUrl作为所需数据366    DatePicker.DrawButton(that, callback);367   }368  }369  else {370   DatePicker.DrawButton(that,callback);371  }372 373 }374 DatePicker.prototype.pick0=function(true_cbrq)//通过代码设置被选中按钮,375 {//如果被选中按钮在另一个月,则日历会自动跳转到相应月份,并且改变被选中按钮的颜色376  var year=parseInt(true_cbrq.substr(0,4));377  var month=parseInt(true_cbrq.substr(4,2));378  var day31=true_cbrq.substr(6,2);379  this.true_cbrq=true_cbrq;380  if(this.year!=year||(this.month+1)!=month)381  {382   this.year=year;383   this.month=month-1;384   this.true_cbrq=true_cbrq;385   this.changeMonth();386   this.changeYear();387   //this.reloadDateList()388 389  }390  else391  {392   if(this.inited)393   {394    this.pick(true_cbrq)395   }396   else {397    this.reloadDateList();398   }399  }400 }401 DatePicker.prototype.pick=function(true_cbrq)//修改被点击按钮的颜色402 {403  if(this.grid_picked)404  {405   this.grid_picked.style.backgroundColor=this.enableBackColor;406 407  }408  var grid=this.obj_enable["div_"+true_cbrq];409  if(grid)410  {411   grid.style.backgroundColor=this.enableBackColorPicked;412   this.grid_picked=grid;413  }414 }415 DatePicker.getDateStr=function(dt)//以下是一些辅助方法416 {417  var arr_day=["","一","二","三","四","五","六","日"];418  var str_date=dt.getFullYear()+"年"+(dt.getMonth()+1)+"月"+dt.getDate()+"日 星期"+arr_day[dt.getDay()];419  return str_date;420 }421 DatePicker.getDateStr2=function(dt)//标准八位日期422 {423  var str_date2=dt.getFullYear()+(dt.getMonth()+1+100+"").substr(1)+(dt.getDate()+100+"").substr(1);424  return str_date2;425 }426 //八位纯数字日期加两个杠,变成十位标准日期427 DatePicker.addGang=function(str)428 {429  var str_res=str.substr(0,4)+"-"+str.substr(4,2)+"-"+str.substr(6,2);430  return str_res;431 }432 //八位纯数字日期加上汉字年月日,并且去掉补位的0433 DatePicker.addNYR=function(str)434 {435  var str_res=str.substr(0,4)+"年"+parseInt(str.substr(4,2))+"月"+parseInt(str.substr(6,2))+"日";436  return str_res;437 }

github地址:https://github.com/ljzc002/SimpleAni

原文转载:http://www.shaoqun.com/a/489767.html

c2c:https://www.ikjzd.com/w/1576

关键词分析工具:https://www.ikjzd.com/w/1968

电霸:https://www.ikjzd.com/w/2597


设计目标:不依赖其他库、兼容一些旧版浏览器、可配置可扩展。测试页面:1<!DOCTYPEhtml>2<htmllang="en">3<head>4<metacharset="UTF-8">5<title>测试日历控件</title>6<style>7#div1{8width:
ensogo:https://www.ikjzd.com/w/1485
燕文物流:https://www.ikjzd.com/w/2229
深圳光明农场农业观光、运动休闲门票多少钱?:http://tour.shaoqun.com/a/39546.html
民间大巴上演"抢客"乱象 一大巴称被竞争对手堵车:http://tour.shaoqun.com/a/63755.html
亚马逊这个仓库暂停收货!首图被禁竟是因为图片政策修改!:https://www.ikjzd.com/home/129988

No comments:

Post a Comment