推荐兼容 IE、 FireFox 的 javascript 日历控件
原创作者:寒羽枫(cityhunter172)
一、简介与声明
此日历控件是 CSDN 网友 KimSoft 的作品:http://blog.csdn.net/kimsoft/archive/2006/05/24/753225.aspx。界面清爽,纯脚本运行,实现了日期的回显功能,最重要的是兼容 FireFox 。
为了适应更多需求,我针对该控件做了以下修改:
1、返回日期的输出格式,我改成了由用户以参数形式指定 Style
2、关于 IE 中 <select> 下拉框的处理,不调用隐藏,而是用<iframe>直接覆盖
3、不使用 //this.panel.style.visibility = "hidden"; 因为它在 FireFox 中会掩盖之前出现过地方下面的链接文字,而是改用 this.panel.style.display = "none";
4、新增失去焦点后,整个 WebCalendar 即隐藏
此控件版权归属于 KimSoft ,大家在使用过程中请勿删除文中的版权声明,谢谢!再次感谢 KimSoft的开源。
[原作者 kimsoft 于2006-11-28 22:00:00 发表:此代码可以任意修改、欢迎传播]
2006 - 12- 03 ,我针对目前出现的BUG 做了以下修正:
1、把原控件中的 <form> 变成<div>,解决不能在页面的 form 标签中引用该脚本的 BUG
2、新增突出已选择的日期的背景色
3、不需要每次使用都初始化实例,整张页面共用一个实例,加快显示速度
二、修改后的代码
以下是 WebCalendar.js 修改后的源码
<!--
var cal;
var isFocus = false ; // 是否为焦点
// 以上为寒羽枫2006-06-25添加的变量
// 选择日期→由寒羽枫2006-06-25添加
function SelectDate(obj,strFormat)
... {
vardate=newDate();
varby=date.getFullYear()-50;//最小值→50年前
varey=date.getFullYear()+50;//最大值→50年后
//cal=newCalendar(by,ey,1,strFormat);//初始化英文版,0 为中文版
cal=(cal==null)?newCalendar(by,ey,1):cal;//不用每次都初始化2006-12-03修正
cal.dateFormatStyle=strFormat;
cal.show(obj);
}
/**/ /**/ /**/ /**
*返回日期
*@paramdthedelimiter
*@parampthepatternofyourdate
2006-06-25由寒羽枫修改为根据用户指定的style来确定;
*/
// String.prototype.toDate=function(x,p){
String.prototype.toDate = function (style) ... {
/**//**//**//*
if(x==null)x="-";
if(p==null)p="ymd";
vara=this.split(x);
vary=parseInt(a[p.indexOf("y")]);
//remembertochangethisnextcentury;)
if(y.toString().length<=2)y+=2000;
if(isNaN(y))y=newDate().getFullYear();
varm=parseInt(a[p.indexOf("m")])-1;
vard=parseInt(a[p.indexOf("d")]);
if(isNaN(d))d=1;
returnnewDate(y,m,d);
*/
vary=this.substring(style.indexOf('y'),style.lastIndexOf('y')+1);//年
varm=this.substring(style.indexOf('M'),style.lastIndexOf('M')+1);//月
vard=this.substring(style.indexOf('d'),style.lastIndexOf('d')+1);//日
if(isNaN(y))y=newDate().getFullYear();
if(isNaN(m))m=newDate().getMonth();
if(isNaN(d))d=newDate().getDate();
vardt;
eval("dt=newDate('"+y+"','"+(m-1)+"','"+d+"')");
returndt;
}
/**/ /**/ /**/ /**
*格式化日期
*@paramdthedelimiter
*@parampthepatternofyourdate
*@authormeizz
*/
Date.prototype.format = function (style) ... {
varo=...{
"M+":this.getMonth()+1,//month
"d+":this.getDate(),//day
"h+":this.getHours(),//hour
"m+":this.getMinutes(),//minute
"s+":this.getSeconds(),//second
"w+":"天一二三四五六".charAt(this.getDay()),//week
"q+":Math.floor((this.getMonth()+3)/3),//quarter
"S":this.getMilliseconds()//millisecond
}
if(/(y+)/.test(style))...{
style=style.replace(RegExp.$1,
(this.getFullYear()+"").substr(4-RegExp.$1.length));
}
for(varkino)...{
if(newRegExp("("+k+")").test(style))...{
style=style.replace(RegExp.$1,
RegExp.$1.length==1?o[k]:
("00"+o[k]).substr((""+o[k]).length));
}
}
returnstyle;
} ;
/**/ /**/ /**/ /**
*日历类
*@parambeginYear1990
*@paramendYear2010
*@paramlang0(中文)|1(英语)可自由扩充
*@paramdateFormatStyle"yyyy-MM-dd";
*@version2006-04-01
*@authorKimSoft(jinqinghua[at]gmail.com)
*@update
*/
function Calendar(beginYear,endYear,lang,dateFormatStyle) ... {
this.beginYear=1990;
this.endYear=2010;
this.lang=0;//0(中文)|1(英文)
this.dateFormatStyle="yyyy-MM-dd";
if(beginYear!=null&&endYear!=null)...{
this.beginYear=beginYear;
this.endYear=endYear;
}
if(lang!=null)...{
this.lang=lang
}
if(dateFormatStyle!=null)...{
this.dateFormatStyle=dateFormatStyle
}
this.dateControl=null;
this.panel=this.getElementById("calendarPanel");
this.container=this.getElementById("ContainerPanel");
this.form=null;
this.date=newDate();
this.year=this.date.getFullYear();
this.month=this.date.getMonth();
this.colors=...{
"cur_word":"#FFFFFF",//当日日期文字颜色
"cur_bg":"#00FF00",//当日日期单元格背影色
"sel_bg":"#FFCCCC",//已被选择的日期单元格背影色2006-12-03寒羽枫添加
"sun_word":"#FF0000",//星期天文字颜色
"sat_word":"#0000FF",//星期六文字颜色
"td_word_light":"#333333",//单元格文字颜色
"td_word_dark":"#CCCCCC",//单元格文字暗色
"td_bg_out":"#EFEFEF",//单元格背影色
"td_bg_over":"#FFCC00",//单元格背影色
"tr_word":"#FFFFFF",//日历头文字颜色
"tr_bg":"#666666",//日历头背影色
"input_border":"#CCCCCC",//input控件的边框颜色
"input_bg":"#EFEFEF"//input控件的背影色
}
this.draw();
this.bindYear();
this.bindMonth();
this.changeSelect();
this.bindData();
}
/**/ /**/ /**/ /**
*日历类属性(语言包,可自由扩展)
*/
Calendar.language = ... {
"year":[[""],[""]],
"months":[["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],
["JAN","FEB","MAR","APR","MAY","JUN","JUL","AUG","SEP","OCT","NOV","DEC"]
],
"weeks":[["日","一","二","三","四","五","六"],
["SUN","MON","TUR","WED","THU","FRI","SAT"]
],
"clear":[["清空"],["CLS"]],
"today":[["今天"],["TODAY"]],
"close":[["关闭"],["CLOSE"]]
}
Calendar.prototype.draw = function () ... {
calendar=this;
varmvAry=[];
//mvAry[mvAry.length]='<formname="calendarForm"style="margin:0px;">';//因<form>不能嵌套,2006-12-01由寒羽枫改用Div
mvAry[mvAry.length]='<divname="calendarForm"style="margin:0px;">';
mvAry[mvAry.length]='<tablewidth="100%"border="0"cellpadding="0"cellspacing="1">';
mvAry[mvAry.length]='<tr>';
mvAry[mvAry.length]='<thalign="left"width="1%"><inputstyle="border:1pxsolid'+calendar.colors["input_border"]+';background-color:'+calendar.colors["input_bg"]+';width:16px;height:20px;"name="prevMonth"type="button"id="prevMonth"value="<"/></th>';
mvAry[mvAry.length]='<thalign="center"width="98%"nowrap="nowrap"><selectname="calendarYear"id="calendarYear"style="font-size:12px;"></select><selectname="calendarMonth"id="calendarMonth"style="font-size:12px;"></select></th>';
mvAry[mvAry.length]='<thalign="right"width="1%"><inputstyle="border:1pxsolid'+calendar.colors["input_border"]+';background-color:'+calendar.colors["input_bg"]+';width:16px;height:20px;"name="nextMonth"type="button"id="nextMonth"value=">"/></th>';
mvAry[mvAry.length]='</tr>';
mvAry[mvAry.length]='</table>';
mvAry[mvAry.length]='<tableid="calendarTable"width="100%"style="border:0pxsolid#CCCCCC;background-color:#FFFFFF"border="0"cellpadding="3"cellspacing="1">';
mvAry[mvAry.length]='<tr>';
for(vari=0;i<7;i++)...{
mvAry[mvAry.length]='<thstyle="font-weight:normal;background-color:'+calendar.colors["tr_bg"]+';color:'+calendar.colors["tr_word"]+';">'+Calendar.language["weeks"][this.lang][i]+'</th>';
}
mvAry[mvAry.length]='</tr>';
for(vari=0;i<6;i++)...{
mvAry[mvAry.length]='<tralign="center">';
for(varj=0;j<7;j++)...{
if(j==0)...{
mvAry[mvAry.length]='<tdstyle="cursor:default;color:'+calendar.colors["sun_word"]+';"></td>';
}elseif(j==6)...{
mvAry[mvAry.length]='<tdstyle="cursor:default;color:'+calendar.colors["sat_word"]+';"></td>';
}else...{
mvAry[mvAry.length]='<tdstyle="cursor:default;"></td>';
}
}
mvAry[mvAry.length]='</tr>';
}
mvAry[mvAry.length]='<trstyle="background-color:'+calendar.colors["input_bg"]+';">';
mvAry[mvAry.length]='<thcolspan="2"><inputname="calendarClear"type="button"id="calendarClear"value="'+Calendar.language["clear"][this.lang]+'"style="border:1pxsolid'+calendar.colors["input_border"]+';background-color:'+calendar.colors["input_bg"]+';width:100%;height:20px;font-size:12px;"/></th>';
mvAry[mvAry.length]='<thcolspan="3"><inputname="calendarToday"type="button"id="calendarToday"value="'+Calendar.language["today"][this.lang]+'"style="border:1pxsolid'+calendar.colors["input_border"]+';background-color:'+calendar.colors["input_bg"]+';width:100%;height:20px;font-size:12px;"/></th>';
mvAry[mvAry.length]='<thcolspan="2"><inputname="calendarClose"type="button"id="calendarClose"value="'+Calendar.language["close"][this.lang]+'"style="border:1pxsolid'+calendar.colors["input_border"]+';background-color:'+calendar.colors["input_bg"]+';width:100%;height:20px;font-size:12px;"/></th>';
mvAry[mvAry.length]='</tr>';
mvAry[mvAry.length]='</table>';
//mvAry[mvAry.length]='</from>';
mvAry[mvAry.length]='</div>';
this.panel.innerHTML=mvAry.join("");
/**//********以下代码由寒羽枫2006-12-01添加**********/
varobj=this.getElementById("prevMonth");
obj.onclick=function()...{calendar.goPrevMonth(calendar);}
obj.onblur=function()...{calendar.onblur();}
this.prevMonth=obj;
obj=this.getElementById("nextMonth");
obj.onclick=function()...{calendar.goNextMonth(calendar);}
obj.onblur=function()...{calendar.onblur();}
this.nextMonth=obj;
obj=this.getElementById("calendarClear");
obj.onclick=function()...{calendar.dateControl.value="";calendar.hide();}
this.calendarClear=obj;
obj=this.getElementById("calendarClose");
obj.onclick=function()...{calendar.hide();}
this.calendarClose=obj;
obj=this.getElementById("calendarYear");
obj.onchange=function()...{calendar.update(calendar);}
obj.onblur=function()...{calendar.onblur();}
this.calendarYear=obj;
obj=this.getElementById("calendarMonth");
with(obj)
...{
onchange=function()...{calendar.update(calendar);}
onblur=function()...{calendar.onblur();}
}this.calendarMonth=obj;
obj=this.getElementById("calendarToday");
obj.onclick=function()...{
vartoday=newDate();
calendar.date=today;
calendar.year=today.getFullYear();
calendar.month=today.getMonth();
calendar.changeSelect();
calendar.bindData();
calendar.dateControl.value=today.format(calendar.dateFormatStyle);
calendar.hide();
}
this.calendarToday=obj;
/**//********以上代码由寒羽枫2006-12-01添加**********/
/**//*
//this.form=document.forms["calendarForm"];
this.form.prevMonth.οnclick=function(){calendar.goPrevMonth(this);}
this.form.nextMonth.οnclick=function(){calendar.goNextMonth(this);}
this.form.prevMonth.οnblur=function(){calendar.onblur();}
this.form.nextMonth.οnblur=function(){calendar.onblur();}
this.form.calendarClear.οnclick=function(){calendar.dateControl.value="";calendar.hide();}
this.form.calendarClose.οnclick=function(){calendar.hide();}
this.form.calendarYear.οnchange=function(){calendar.update(this);}
this.form.calendarMonth.οnchange=function(){calendar.update(this);}
this.form.calendarYear.οnblur=function(){calendar.onblur();}
this.form.calendarMonth.οnblur=function(){calendar.onblur();}
this.form.calendarToday.οnclick=function(){
vartoday=newDate();
calendar.date=today;
calendar.year=today.getFullYear();
calendar.month=today.getMonth();
calendar.changeSelect();
calendar.bindData();
calendar.dateControl.value=today.format(calendar.dateFormatStyle);
calendar.hide();
}
*/
}
// 年份下拉框绑定数据
Calendar.prototype.bindYear = function () ... {
//varcy=this.form.calendarYear;
varcy=this.calendarYear;//2006-12-01由寒羽枫修改
cy.length=0;
for(vari=this.beginYear;i<=this.endYear;i++)...{
cy.options[cy.length]=newOption(i+Calendar.language["year"][this.lang],i);
}
}
// 月份下拉框绑定数据
Calendar.prototype.bindMonth = function () ... {
//varcm=this.form.calendarMonth;
varcm=this.calendarMonth;//2006-12-01由寒羽枫修改
cm.length=0;
for(vari=0;i<12;i++)...{
cm.options[cm.length]=newOption(Calendar.language["months"][this.lang][i],i);
}
}
// 向前一月
Calendar.prototype.goPrevMonth = function (e) ... {
if(this.year==this.beginYear&&this.month==0)...{return;}
this.month--;
if(this.month==-1)...{
this.year--;
this.month=11;
}
this.date=newDate(this.year,this.month,1);
this.changeSelect();
this.bindData();
}
// 向后一月
Calendar.prototype.goNextMonth = function (e) ... {
if(this.year==this.endYear&&this.month==11)...{return;}
this.month++;
if(this.month==12)...{
this.year++;
this.month=0;
}
this.date=newDate(this.year,this.month,1);
this.changeSelect();
this.bindData();
}
// 改变SELECT选中状态
Calendar.prototype.changeSelect = function () ... {
//varcy=this.form.calendarYear;
//varcm=this.form.calendarMonth;
varcy=this.calendarYear;//2006-12-01由寒羽枫修改
varcm=this.calendarMonth;
for(vari=0;i<cy.length;i++)...{
if(cy.options[i].value==this.date.getFullYear())...{
cy[i].selected=true;
break;
}
}
for(vari=0;i<cm.length;i++)...{
if(cm.options[i].value==this.date.getMonth())...{
cm[i].selected=true;
break;
}
}
}
// 更新年、月
Calendar.prototype.update = function (e) ... {
//this.year=e.form.calendarYear.options[e.form.calendarYear.selectedIndex].value;
//this.month=e.form.calendarMonth.options[e.form.calendarMonth.selectedIndex].value;
this.year=e.calendarYear.options[e.calendarYear.selectedIndex].value;//2006-12-01由寒羽枫修改
this.month=e.calendarMonth.options[e.calendarMonth.selectedIndex].value;
this.date=newDate(this.year,this.month,1);
this.changeSelect();
this.bindData();
}
// 绑定数据到月视图
Calendar.prototype.bindData = function () ... {
varcalendar=this;
vardateArray=this.getMonthViewArray(this.date.getYear(),this.date.getMonth());
vartds=this.getElementById("calendarTable").getElementsByTagName("td");
for(vari=0;i<tds.length;i++)...{
//tds[i].style.color=calendar.colors["td_word_light"];
tds[i].style.backgroundColor=calendar.colors["td_bg_out"];
tds[i].onclick=function()...{return;}
tds[i].onmouseover=function()...{return;}
tds[i].onmouseout=function()...{return;}
if(i>dateArray.length-1)break;
tds[i].innerHTML=dateArray[i];
if(dateArray[i]!=" ")...{
tds[i].onclick=function()...{
if(calendar.dateControl!=null)...{
calendar.dateControl.value=newDate(calendar.date.getFullYear(),
calendar.date.getMonth(),
this.innerHTML).format(calendar.dateFormatStyle);
}
calendar.hide();
}
tds[i].onmouseover=function()...{
this.style.backgroundColor=calendar.colors["td_bg_over"];
}
tds[i].onmouseout=function()...{
this.style.backgroundColor=calendar.colors["td_bg_out"];
}
if(newDate().format(calendar.dateFormatStyle)==
newDate(calendar.date.getFullYear(),
calendar.date.getMonth(),
dateArray[i]).format(calendar.dateFormatStyle))...{
//tds[i].style.color=calendar.colors["cur_word"];
tds[i].style.backgroundColor=calendar.colors["cur_bg"];
tds[i].onmouseover=function()...{
this.style.backgroundColor=calendar.colors["td_bg_over"];
}
tds[i].onmouseout=function()...{
this.style.backgroundColor=calendar.colors["cur_bg"];
}
//continue;//若不想当天单元格的背景被下面的覆盖,请取消注释→2006-12-03寒羽枫添加
}//endif
//设置已被选择的日期单元格背影色2006-12-03寒羽枫添加
if(calendar.dateControl!=null&&calendar.dateControl.value==newDate(calendar.date.getFullYear(),
calendar.date.getMonth(),
dateArray[i]).format(calendar.dateFormatStyle))...{
tds[i].style.backgroundColor=calendar.colors["sel_bg"];
tds[i].onmouseover=function()...{
this.style.backgroundColor=calendar.colors["td_bg_over"];
}
tds[i].onmouseout=function()...{
this.style.backgroundColor=calendar.colors["sel_bg"];
}
}
}
}
}
// 根据年、月得到月视图数据(数组形式)
Calendar.prototype.getMonthViewArray = function (y,m) ... {
varmvArray=[];
vardayOfFirstDay=newDate(y,m,1).getDay();
vardaysOfMonth=newDate(y,m+1,0).getDate();
for(vari=0;i<42;i++)...{
mvArray[i]=" ";
}
for(vari=0;i<daysOfMonth;i++)...{
mvArray[i+dayOfFirstDay]=i+1;
}
returnmvArray;
}
// 扩展document.getElementById(id)多浏览器兼容性frommeizztreesource
Calendar.prototype.getElementById = function (id) ... {
if(typeof(id)!="string"||id=="")returnnull;
if(document.getElementById)returndocument.getElementById(id);
if(document.all)returndocument.all(id);
try...{returneval(id);}catch(e)...{returnnull;}
}
// 扩展object.getElementsByTagName(tagName)
Calendar.prototype.getElementsByTagName = function (object,tagName) ... {
if(document.getElementsByTagName)returndocument.getElementsByTagName(tagName);
if(document.all)returndocument.all.tags(tagName);
}
// 取得HTML控件绝对位置
Calendar.prototype.getAbsPoint = function (e) ... {
varx=e.offsetLeft;
vary=e.offsetTop;
while(e=e.offsetParent)...{
x+=e.offsetLeft;
y+=e.offsetTop;
}
return...{"x":x,"y":y};
}
// 显示日历
Calendar.prototype.show = function (dateObj,popControl) ... {
if(dateObj==null)...{
thrownewError("arguments[0]isnecessary")
}
this.dateControl=dateObj;
//if(dateObj.value.length>0){
//this.date=newDate(dateObj.value.toDate());
//this.date=newDate(dateObj.value.toDate(this.dateFormatStyle));//由寒羽枫修改,带入用户指定的style
this.date=(dateObj.value.length>0)?newDate(dateObj.value.toDate(this.dateFormatStyle)):newDate();//2006-12-03寒羽枫添加→若为空则显示当前月份
this.year=this.date.getFullYear();
this.month=this.date.getMonth();
this.changeSelect();
this.bindData();
//}
if(popControl==null)...{
popControl=dateObj;
}
varxy=this.getAbsPoint(popControl);
this.panel.style.left=xy.x-25+"px";
this.panel.style.top=(xy.y+dateObj.offsetHeight)+"px";
//由寒羽枫2006-06-25修改→把visibility变为display,并添加失去焦点的事件
//this.setDisplayStyle("select","hidden");
//this.panel.style.visibility="visible";
//this.container.style.visibility="visible";
this.panel.style.display="";
this.container.style.display="";
dateObj.onblur=function()...{calendar.onblur();}
this.container.onmouseover=function()...{isFocus=true;}
this.container.onmouseout=function()...{isFocus=false;}
}
// 隐藏日历
Calendar.prototype.hide = function () ... {
//this.setDisplayStyle("select","visible");
//this.panel.style.visibility="hidden";
//this.container.style.visibility="hidden";
this.panel.style.display="none";
this.container.style.display="none";
isFocus=false;
}
// 焦点转移时隐藏日历→由寒羽枫2006-06-25添加
Calendar.prototype.onblur = function () ... {
if(!isFocus)...{this.hide();}
}
// 以下由寒羽枫2006-06-25修改→用<iframe>遮住IE的下拉框
/**/ /**/ /**/ /*
//设置控件显示或隐藏
Calendar.prototype.setDisplayStyle=function(tagName,style){
vartags=this.getElementsByTagName(null,tagName)
for(vari=0;i<tags.length;i++){
if(tagName.toLowerCase()=="select"&&
(tags[i].name=="calendarYear"||
tags[i].name=="calendarMonth")){
continue;
}
//tags[i].style.visibility=style;
tags[i].style.display=style;
}
}
*/
// document.write('<divid="ContainerPanel"style="visibility:hidden"><divid="calendarPanel"style="position:absolute;visibility:hidden;z-index:9999;');
document.write( ' <divid="ContainerPanel"style="display:none"><divid="calendarPanel"style="position:absolute;display:none;z-index:9999; ' );
document.write( ' background-color:#FFFFFF;border:1pxsolid#CCCCCC;width:175px;font-size:12px;"></div> ' );
if (document.all)
... {
document.write('<iframestyle="position:absolute;z-index:2000;width:expression(this.previousSibling.offsetWidth);');
document.write('height:expression(this.previousSibling.offsetHeight);');
document.write('left:expression(this.previousSibling.offsetLeft);top:expression(this.previousSibling.offsetTop);');
document.write('display:expression(this.previousSibling.style.display);"scrolling="no"frameborder="no"></iframe>');
}
document.write( ' </div> ' );
// varcalendar=newCalendar();//此句被寒羽枫注释,否则IE将报错
// 调用calendar.show(dateControl,popControl);
// -->
三、调用方法
1、引用 WebCalendar.js
< script src ="js/WebCalendar.js" type ="text/javascript" ></ script >2、编写触发的脚本事件
this .Txt_Date.Attributes[ " onclick " ] = " SelectDate(this,'yyyy-MM-dd') " ;
< input name ="Txt_Date" type ="text" maxlength ="10" id ="Txt_Date" onclick ="SelectDate(this,'yyyy/MM/dd')" />