上次写了一个《自己动手做WEB控件》引来众多网友评论,更有几个朋友指出问题,非常感谢大家。
其实上篇只是一个简单的用户自定义控件,后来项目中的日历我是用JS重写的,并且用的是WEB控件,现贴出来同大家分享:
JS:
// JScript 文件
<!--
//本程序根据好友提供的代码改造而来!
//wrt by lw 2010-3-8
var preImg_Month="";
var preImg_Year="";
var nextImg_Month="";
var nextImg_Year="";
var curShowCalendar; //当前激活的日历控件
var allowCloseCalendar = 0; //是否允许关闭当前激活的日历控件
//显示日历:
function activeCalendar(inputControlID,language,imgObj)
{
eval(inputControlID+"_obj=new createCalendarObject('"+inputControlID+"')");
eval(inputControlID+"_obj.calendarSpan=imgObj.nextSibling");
eval(inputControlID+"_obj.language='"+language+"'");
eval(inputControlID+"_obj.showDateTable()");
}
//显示日历选择表:
function showDateTable()
{
this.calendarSpan.style.visibility="visible";
this.calendarSpan.style.border="2px solid #cacaca";
this.createDateTable();
}
//创建日历选择框:
function createDateTable()
{
var str="";
var obj=this;
// str+=" <table οnmοuseοver='"+this.inputID+"_obj.stopTimer();' οnmοuseοut='"+this.inputID+"_obj.startTimer()'>"; //使用定时关闭
str+=" <table style=/"font-size:16px/">";
var preMonth=this.month - 1;
if(preMonth <=0)
preMonth=12;
var nextMonth=this.month + 1;
if(nextMonth>12)
nextMonth=1;
str+="<tr bgcolor=#d0d1f6 οnclick='allowCloseCalendar = 0;'> " +
"<td align='center' οnclick='allowCloseCalendar = 0;'>" +
"<img title='" + Number(this.year-1) + "' οnmοuseοver='this.style.cursor=/"pointer/"' src='" + preImg_Year + "' οnclick='"
+this.inputID+"_obj.goToPrevYear()' />" +
"</td>" +
"<td align='center' οnclick='allowCloseCalendar = 0;'>" +
"<img title='"+Number(preMonth) + "' οnmοuseοver='this.style.cursor=/"pointer/"' src='" + preImg_Month +
"'οnclick='"+this.inputID + "_obj.goToPrevMonth()' />" +
"</td>" +
"<td colspan='3' align='center' οnclick='allowCloseCalendar = 0;'>"+this.year + "年" + this.month + "月" +
"</td>" +
"<td align='center' οnclick='allowCloseCalendar = 0;'>" +
"<img title=/""+nextMonth+"/" οnmοuseοver='this.style.cursor=/"pointer/"' src='" + nextImg_Month
+"' οnclick='"+this.inputID+"_obj.goToNextMonth()' />" +
"</td>" +
"<td align='center' οnclick='allowCloseCalendar = 0;'>" +
"<img title='"+Number(this.year+1) + "' οnmοuseοver='this.style.cursor=/"pointer/"' src='" + nextImg_Year
+"' οnclick='"+this.inputID+"_obj.goToNextYear()' />" +
"</td></tr>";
var langRow="";
if(this.language=="en")
langRow="<tr bgcolor=#d0d1f6 οnclick='allowCloseCalendar = 0;'><td οnclick='allowCloseCalendar = 0;'>Su</td>" +
"<td οnclick='allowCloseCalendar = 0;'>Mo</td><td οnclick='allowCloseCalendar = 0;'>Tu</td>" +
"<td οnclick='allowCloseCalendar = 0;'>We</td><td οnclick='allowCloseCalendar = 0;'>Th</td>" +
"<td οnclick='allowCloseCalendar = 0;'>Fr</td><td οnclick='allowCloseCalendar = 0;'>Sa</td></tr>";
if(this.language=="zh")
langRow="<tr bgcolor=#f6e7d0 οnclick='allowCloseCalendar = 0;'>" +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>日</td> " +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>一</td>" +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>二</td>" +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>三</td>" +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>四</td>" +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>五</td>" +
"<td οnclick='allowCloseCalendar = 0;' align='center' width=30px>六</td> </tr>";
str += langRow;
var monthDaysArr = [31,28,31,30,31,30,31,31,30,31,30,31];
var dateObj = new Date(this.year,this.month-1,1);
var firstDay = dateObj.getDay();
var dayCountAtFirstRow = 7 - firstDay; //第1行的天数
var rowCount=0;
//闰年的计算方法:公元纪年的年数可以被四整除,即为闰年;被100整除而不能被400整除为平年;被100整除也可被400整除的为闰年。
var daysOfThisMonth; //本月天数
if (this.month == 2)
daysOfThisMonth = ((0 == this.year % 4) && (0 != (this.year % 100))) ||(0 == this.year % 400) ? 29 : 28;
else
daysOfThisMonth = monthDaysArr[this.month-1];
var restDayCount = daysOfThisMonth - dayCountAtFirstRow; //除第1行外的天数
//今天:
var today = new Date();
var todayDate = today.getDate();
var todayYear = today.getFullYear();
var todayMonth = today.getMonth()+1;
if(restDayCount%7==0)
rowCount=restDayCount/7+1;
else
rowCount=Math.floor(restDayCount/7)+2;
for(var i=0;i <rowCount;i++)
{
if(i==0) //第一行特殊处理
{
str+="<tr οnclick='allowCloseCalendar = 0;'>";
for(var k=1;k <=7;k++)
{
if (k <= firstDay)
str+=" <td οnclick='allowCloseCalendar = 0;'></td>";
else
{
if(this.year==todayYear && this.month==todayMonth && (k-firstDay)==todayDate) //今天特殊显示
str+="<td align='center' style='background:red;' οnmοuseοver='this.style.cursor=/"pointer/";" +
"this.style.borderLeft=/"1px solid gray/";this.style.borderTop=/"1px solid gray/";' " +
"οnmοuseοut='this.style.borderLeft=/"0px solid white/";this.style.borderTop=/"0px solid white/";'" +
" οnclick='"+this.inputID+"_obj.fillInDate(/""+(k-firstDay)+"/")'>"+(k-firstDay)+
"</td>";//οnmοuseοut='this.style.borderLeft=/"1px solid white/";this.style.borderTop=/"1px solid white/"'
else
str+="<td align='center' οnmοuseοver='this.style.cursor=/"pointer/";this.style.borderLeft=/"1px solid gray/";" +
"this.style.borderTop=/"1px solid gray/";' οnmοuseοut='this.style.borderLeft=/"0px solid white/";" +
"this.style.borderTop=/"0px solid white/";' " +
"οnclick='"+this.inputID+"_obj.fillInDate(/""+(k-firstDay)+"/")'>"+(k-firstDay) +
"</td>";//οnmοuseοut='this.style.borderLeft=/"1px solid white/";this.style.borderTop=/"1px solid white/"'
}
}
str+=" </tr>";
}
else
{
str+=" <tr οnclick='allowCloseCalendar = 0;'>";
for(var k=1;k <=7;k++)
{
var currentDay=(i-1)*7+k+dayCountAtFirstRow;
if(currentDay <= daysOfThisMonth)
{
if(this.year==todayYear&&this.month==todayMonth&¤tDay==todayDate) //今天特殊显示
str += "<td align='center' style='background:red;' οnmοuseοver='this.style.cursor=/"pointer/";" +
"this.style.borderLeft=/"1px solid gray/";this.style.borderTop=/"1px solid gray/";'" +
" οnmοuseοut='this.style.borderLeft=/"0px solid white/";this.style.borderTop=/"0px solid white/";' " +
"οnclick='"+this.inputID+"_obj.fillInDate(/""+currentDay+"/")'>"+currentDay+"</td>" ;
else
str+=" <td align='center' οnmοuseοver='this.style.cursor=/"pointer/";this.style.borderLeft=/"1px solid gray/";" +
"this.style.borderTop=/"1px solid gray/";' οnmοuseοut='this.style.borderLeft=/"0px solid white/";" +
"this.style.borderTop=/"0px solid white/";' " +
"οnclick='"+this.inputID+"_obj.fillInDate(/""+currentDay+"/")'>"+currentDay+"</td>" ;
}
else
{
str += "<td οnclick='allowCloseCalendar = 0;'></td>";
}
}
str+=" </tr>";
}
}
str+=" </table>";
this.calendarSpan.innerHTML=str;
// //调试用的文本框:
// var p = document.getElementById("TextBox1");
// p.value = str;
// this.stopTimer();
}
//前一月:
//wrt by lw 2010-3-8
function goToPrevMonth()
{
if(this.month > 1)
this.month--;
else
{
this.month=12;
this.year--;
}
this.createDateTable();
}
//前一年:
function goToPrevYear()
{
this.year--;
this.month=12;
this.createDateTable();
}
//后一月:
function goToNextMonth()
{
if(this.month <12)
this.month++;
else
{
this.month=1;
this.year++;
}
this.createDateTable();
}
//后一年:
function goToNextYear()
{
this.year++;
this.month=1;
this.createDateTable();
}
//显示选择的日历:
function fillInDate(date)
{
this.inputControl.value=this.year+"-"+this.month+"-"+date;
this.calendarSpan.style.visibility="hidden";
}
//关闭弹出窗口:
function closeMe()
{
if (this.calendarSpan != null)
this.calendarSpan.style.visibility="hidden";
}
//创建日历对象:
function createCalendarObject(inputControlID)
{
this.inputID=inputControlID;
this.language="zh";
this.format="YYYY-MM-DD";
var today=new Date();
this.year=today.getFullYear();
this.month=today.getMonth()+1;
this.date=today.getDate();
this.day=today.getDay();
this.calendarSpan=null;
this.interval=null;
this.inputControl=document.getElementById(this.inputID);
this.createDateTable=createDateTable;
this.goToPrevMonth=goToPrevMonth;
this.goToPrevYear=goToPrevYear;
this.goToNextMonth=goToNextMonth;
this.goToNextYear=goToNextYear;
this.showDateTable=showDateTable;
this.fillInDate=fillInDate;
curShowCalendar = this;
allowCloseCalendar = 0;
this.closeMe = closeMe;
//自动定时关闭
// this.startTimer=startTimer;
// this.stopTimer=stopTimer;
}
//在其他地方鼠标click关闭日历:
//wrt by lw 2010-3-8
function document.onclick()
{
if(allowCloseCalendar == 1 && curShowCalendar != null)
{
curShowCalendar.closeMe();
curShowCalendar = null;
}
else
{
allowCloseCalendar= 1;
}
}
var isKeyDownClear=0; //清除按键的判断开关量
//按ESC键关闭日历:
//wrt by lw 2010-3-8
function document.onkeydown()
{
var e = event? event:window.event;
if(e.keyCode == 27 && curShowCalendar != null)
curShowCalendar.closeMe();
}
//日期格式检查:
//wrt by lw 2010-3-8
function regexpCheck()
{
e = event? event:window.event;
if (e.keyCode == 13 || e.keyCode == 9)
{
var s = e.srcElement.value;
// //格式:YYYY-MM-DD
// var r= new RegExp("(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})" +
// "[-/](((0[13578]|1[02])[-/](0[1-9]|[12][0-9]|3[01]))" + //大月
// "|((0[469]|11)[-/](0[1-9]|[12][0-9]|30))" + //小月
// "|(02[-/](0[1-9]|[1][0-9]|2[0-8]))))" + //2月28号以前的日期
// "|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))[-/]02[-/]29)");//闰年处理
// if (!(r.test(s) && s.match(r)[0]==s))
// {
// e.srcElement.value = "你输入的日期格式不对!";
// e.srcElement.select();
// e.srcElement.focus();
// }
var r= new Array;
//格式:YYYY-MM-DD:
r[0] = new RegExp("(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})" +
"[-/](((0[13578]|1[02])[-/](0[1-9]|[12][0-9]|3[01]))" + //大月
"|((0[469]|11)[-/](0[1-9]|[12][0-9]|30))" + //小月
"|(02[-/](0[1-9]|[1][0-9]|2[0-8]))))" + //2月28号以前的日期
"|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))[-/]02[-/]29)");//闰年处理
//格式:YYYY-M-DD:
r[1] = new RegExp("(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})" +
"[-/](([13578][-/](0[1-9]|[12][0-9]|3[01]))" + //大月
"|([469][-/](0[1-9]|[12][0-9]|30))" + //小月
"|(2[-/](0[1-9]|[1][0-9]|2[0-8]))))" + //2月28号以前的日期
"|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))[-/]2[-/]29)");//闰年处理
//格式:YYYY-MM-D:
r[2] = new RegExp("([0-9]{4}[-/](0[123456789]|1[012])[-/][1-9])");
//格式:YYYY-M-D:
r[3] = new RegExp("([0-9]{4}[-/][123456789][-/][1-9])");
for (var i = 0; i < 4; i++)
{
if (r[i].test(s) && s.match(r[i])[0]==s)
{
r = null;
return true;
}
}
e.srcElement.value = "你输入的日期格式不对!";
e.srcElement.select();
e.srcElement.focus();
r = null;
e.keyCode = 0;
e.returnValue=false;
return false;
}
}
//-->
js代码感谢limii提供的思路,我修正了一些错误,增加了窗口关闭的处理,原来他给的方案自动定时关闭不好;另增加了日期的格式检查,现基本可以处理1600年内的闰年了,但是好像更多的情况还有些问题。欢迎大家讨论。
后台的构造函数如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
[assembly: WebResource("myTools.images.calendar.jpg", "image/jpeg")]
[assembly: WebResource("myTools.images.calendar_next.gif", "image/gif")]
[assembly: WebResource("myTools.images.calendar_nextYear.gif", "image/gif")]
[assembly: WebResource("myTools.images.calendar_prev.gif", "image/gif")]
[assembly: WebResource("myTools.images.calendar_prevYear.gif", "image/gif")]
[assembly: WebResource("myTools.scripts.calendar.js", "application/x-javascript")]
namespace myTools
{
//[DefaultProperty("Date")]
[ToolboxData("<{0}:myCalendar runat=server></{0}:myCalendar>")]
[System.Drawing.ToolboxBitmap(typeof(myTools.Resources.Icon), "calendar.jpg")]
public class myCalendar : Control
{
//选择的日期:
private string _date = "";
public string Date
{
get { return this._date; }
set { this._date = value; }
}
//日期语言:
public enum DateLang { en, zh };
private DateLang language = DateLang.zh;
public DateLang Language
{
get { return this.language; }
set { this.language = value; }
}
//日期格式:
private string format = "YYYY-MM-DD";//DateFormat.format1;
public string Format
{
get { return this.format; }
set { this.format = value; }
}
//输入栏宽度:
private string _width = "100px";
public string width
{
get { return this._width; }
set { this._width = value; }
}
protected override void Render(HtmlTextWriter writer)
{
string imgPath = Page.ClientScript.GetWebResourceUrl(this.GetType(), "myTools.images.calendar.jpg");
string strControl = "<input type='text' name='" + this.ID + "' id='" + this.ID + "' " +
" value='" + _date + "' οnkeydοwn='regexpCheck();' style=/"width:" + _width + "/" />" + //输入框'
"<img src='" + imgPath + "' οnmοuseοver='this.style.cursor=/"pointer/"'" +
" οnclick='activeCalendar(/"" + this.ID + "/",/"" + this.Language.ToString() + "/",this)'/>" + //下拉按钮
"<span id='dateSpan_" + this.ID + "' style='position:absolute;z-index:9999;width:240px;height:180px;" + //弹出窗口
"border:2px solid gray;background:#E5E7EB;visibility:hidden;margin:0 auto;'>" +
"</span>";
writer.Write(strControl);
}
protected override void OnLoad(EventArgs e)
{
if (Page.IsPostBack)
this.Date = Page.Request[this.ID];
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
//注入JS:
ClientScriptManager cs = Page.ClientScript;
cs.RegisterClientScriptResource(this.GetType(), "myTools.scripts.calendar.js");
//注入图片:
string prevMonth = Page.ClientScript.GetWebResourceUrl(this.GetType(), "myTools.images.calendar_prev.gif");
string prevYear = Page.ClientScript.GetWebResourceUrl(this.GetType(), "myTools.images.calendar_prevYear.gif");
string nextMonth = Page.ClientScript.GetWebResourceUrl(this.GetType(), "myTools.images.calendar_next.gif");
string nextYear = Page.ClientScript.GetWebResourceUrl(this.GetType(), "myTools.images.calendar_nextYear.gif");
Page.ClientScript.RegisterStartupScript(this.GetType(), "image", "<script type='text/javascript'>preImg_Month='" + prevMonth
+ "';preImg_Year='" + prevYear + "';nextImg_Month='" + nextMonth + "';nextImg_Year='" + nextYear + "'</script>");
}
}
}
整个项目的文件我打包放在了我的资源空间里了,需要使用的朋友请去下载!