|
热门文章 |
|
|
|
|
JCalendar 日历控件 v1.0 beta |
来源:蓝色理想 更新时间:2010/8/29 23:25:24 阅读次数: 我要投稿 |
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Language" content="zh-cn" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JCalendar 日历控件 v1.0 beta</title> <style type="text/css"> body { font-size:12px; font-family:'Lucida Grande','Lucida Sans Unicode','宋体',arial,verdana,sans-serif; } input,select{ border:1px solid #369; font-size:12px; margin:0 5px; } input { width:180px; } fieldset { margin:5px; padding:0 12px 12px 12px; border:1px solid #D4D4D4; background-color:#F9F9F9; } legend { font-weight:bold; } .center { text-align:center; } .red { color:#F00; } /**********日历样式开始********************/ #calendar_container { width:160px; border:1px solid #06C; } #calendar { border-collapse:collapse; background-color:#FFF; width:160px; height:120px; margin:0px auto; cursor:default; } #calendar td { font-size:12px; text-align:center; vertical-align:middle; font-family:"宋体"; } #calendar thead { background-color:#999; color:#FFF; } #calendar caption { background-color:#06C; } #calendar a{ color:#F90; margin:0 5px; text-decoration:none; } #calendar #prev_month,#calendar #next_month { font-size:18px; margin:0; } #calendar #c_today { background-color:#036; color:#FFF; } #calendar .over { background-color:#CCC; } #calendar .keydate { color:#06F; } </style> <script type="text/javascript" defer="defer"> //////////////////基本函数库///////////////////////////// var isIE = /msie/i.test(navigator.userAgent); var isDTD = /CSS1Compat/i.test(document.compatMode); if(!isIE){ window.constructor.prototype.__defineGetter__("event",function(){ var func = arguments.callee.caller; while(func != null){ var arg0 = func.arguments[0]; if(arg0 && (arg0.constructor==Event || arg0.constructor ==MouseEvent)){ return arg0; } func = func.caller; } return null; }); Event.prototype.__defineSetter__("returnValue",function(b){ if(!b)this.preventDefault(); return b; }); Event.prototype.__defineGetter__("srcElement",function(){ var node=this.target; while(node.nodeType != 1)node=node.parentNode; return node; }); Event.prototype.__defineGetter__("offsetX",function(){ return this.layerX; }); Event.prototype.__defineGetter__("offsetY",function(){ return this.layerY; }); HTMLElement.prototype.attachEvent = function(sType,foo){ this.addEventListener(sType.slice(2),foo,false); } HTMLElement.prototype.detachEvent = function(sType,foo){ this.removeEventListener(sType.slice(2),foo,false); } HTMLDocument.prototype.attachEvent = function(sType,foo){ this.addEventListener(sType.slice(2),foo,false); } HTMLDocument.prototype.detachEvent = function(sType,foo){ this.removeEventListener(sType.slice(2),foo,false); } HTMLElement.prototype.__defineGetter__("innerText",function(){ return this.textContent; }); HTMLElement.prototype.__defineSetter__("innerText",function(str){ this.textContent = str; }); } else document.execCommand("BackgroundImageCache",false,true); function $(id){return (typeof id == "string" ? document.getElementById(id) : id);} function $N(name){return document.getElementsByName(name);} function $TN(name,root){return root ? $(root).getElementsByTagName(name) : document.getElementsByTagName(name);} function $DC(name){return document.createElement(name);} function exist(id){return $(id)!= null;} function hide(){ for(var i = 0; i < arguments.length; i++){ if(exist(arguments[i])){ if($(arguments[i]).style.visibility) $(arguments[i]).style.visibility = "hidden"; else $(arguments[i]).style.display = "none"; } } } function show(){ for(var i = 0; i < arguments.length; i++){ if(exist(arguments[i])){ if($(arguments[i]).style.visibility) $(arguments[i]).style.visibility="visible"; else $(arguments[i]).style.display = ""; } } } </script> <script type="text/javascript" defer="defer"> //////////////JCalendar 类//////////////////////////// /*************************** *JCalendar日历控件 *@author brull *@email [email]brull@163.com[/email] *@date 2007-4-16 *@更新 2007-5-27 *@version 1.0 beta ***************************/ /* *@param year 年份,[可选] *@param month 月份,[可选] *@param date 日期,[可选] *或者是以横线间隔开的日期,比如:2007-4-27 */ function JCalendar (year,month,date) { if($("calendar"))return;//唯一实例 var _date = null; if(arguments.length == 3) _date = new Date(year,month-1,date); else if(arguments.length == 1 && typeof arguments[0] == "string") _date = eval("new Date(" + arguments[0].split("-").join() + ")"); //如果没有参数,就初始化为当天日期 else if(arguments.length == 0) _date = new Date(); this.year = _date.getFullYear(); this.month = _date.getMonth() + 1; this.date = _date.getDate(); this.FIRSTYEAR = 1949; this.LASTYEAR = 2049; JCalendar.cur_year = this.year; JCalendar.cur_month = this.month; JCalendar.cur_date = this.date; JCalendar.cur_obj_id = null;//作为输入控件时保存当前文本框的id } /** *设置日历年份下拉菜单的年份范围 *@first 第一个年份界限 *@last 第二个年份界限 *两个参数顺序可以颠倒 */ JCalendar.prototype.setYears = function(first,last){ if(isNaN(first) || isNaN(last)) return; this.FIRSTYEAR = Math.min(first,last); this.LASTYEAR = Math.max(first,last); } /** *以HTML串返回日历控件的HTML代码 */ JCalendar.prototype.toString = function(){ var fday = new Date(this.year,this.month-1,1).getDay();//每月第一天的星期数 var select_year = new Array();//年份下拉菜单 var select_month = new Array();//月份下拉菜单 //日历里的每个单元格的数据,预先定义一段空数组,对应日历里第一周空的位置。[注意星期天对应的数是0] var date = new Array(fday > 0 ? fday - 1 : 0); var dayNum = new Date(this.year,this.month,0).getDate();//每月的天数 var html_str = new Array();//保存日历控件的HTML代码 var date_index = 0;//date数组的索引 var weekDay = ["日","一","二","三","四","五","六"]; //填充年份下拉菜单 select_year.push("<select id='select_year' style='display:none' onblur =\"hide(this);show('title_year')\" onchange='JCalendar.update(this.value,JCalendar.cur_month)'>"); for(var i = this.FIRSTYEAR; i <= this.LASTYEAR; i++){ if(i == this.year) select_year.push("<option value='" + i + "' selected='selected'>" + i +"</option>"); else select_year.push("<option value='" + i + "'>" + i +"</option>"); } select_year.push("</select>"); //填充月份下拉菜单 select_month.push("<select id='select_month' style='display:none' onblur =\"hide(this);show('title_month')\" onchange='JCalendar.update(JCalendar.cur_year,this.value)'>"); for(var i = 1; i <= 12; i++){ if(i == this.month) select_month.push("<option value='" + i + "' selected='selected'>" + i +"月</option>"); else select_month.push("<option value='" + i + "'>" + i +"月</option>"); } select_month.push("</select>"); //初始化date数组 for(var j = 1; j <= dayNum; j++){ date.push(j); } //开始构建日历控件的HTML代码 html_str.push("<table id='calendar'>"); //日历表格caption html_str.push("<caption>" + "<a href='#' id='prev_month' title='上一月份' onclick=\"JCalendar.update(JCalendar.cur_year,JCalendar.cur_month-1);return false;\">«</a><a href='#' id='title_year' title='点击选择年份' onclick=\"hide(this);show('select_year');$('select_year').focus();return false\">" + this.year + "年</a>" + select_year.join("") + "<a href='#' id='title_month' title='点击选择月份' onclick=\"hide(this);show('select_month');$('select_month').focus();return false\">" + this.month + "月</a>" + select_month.join("") + "<a href='#' id='next_month' title='下一月份' onclick=\"JCalendar.update(JCalendar.cur_year,JCalendar.cur_month+1);return false;\">»</a></caption>"); //日历表格头 html_str.push("<thead><tr>"); for(var i = 0; i < 7; i++){//填充日历头 html_str.push("<td>" + weekDay[i] + "</td>"); } html_str.push("</tr></thead>"); //日历主体 var tmp; html_str.push("<tbody>"); for(var i = 0; i < 6; i++){//填充日期,6行7列 html_str.push("<tr>"); for(var j = 0; j < 7; j++){ tmp = date[date_index++]; if(!tmp) tmp = ""; html_str.push("<td "); if(tmp == this.date) html_str.push("id='c_today' "); html_str.push("onmouseover='JCalendar.over(this)' onmouseout='JCalendar.out(this)' onclick='JCalendar.click(this)'>" + tmp + "</td>"); } html_str.push("</tr>"); } html_str.push("</tbody></table>"); return html_str.join(""); } /** *特别显示关键天,典型例子博客的日历 * 实现原理,为每个关键天的表格单元添加一个class,名字为keydate,CSS样式需要自己写,比如加个背景之类的 *@param 日期的数组,比如:[1,4,6,9] */ JCalendar.prototype.setKeyDate = function(){ var dates = arguments[0]; var tds = $TN("td",$("calendar")); var reg = null; for(var i = 0; i < dates.length; i++){ reg = new RegExp("\\b" + dates[i] + "\\b"); for(var j = 7; j < tds.length; j++){//忽略表格头 if(reg.test(tds[j].innerText)){ tds[j].className = "keydate"; break; } } } } /** *可以将日历控件邦定到某个文本框,在点击文本框的时候,会在direction指定的方向弹出日历,可以多次调用来帮定多个文本框 *@ param obj_id 需要邦定日历的文本框的id *@ param direction 日历出现的相对于文本框的方向 [可选] 默认为right */ JCalendar.prototype.bind = function(obj_id,direction){ var obj = $(obj_id); var direction = direction ? direction : "right"; if(!obj)return; if(!$("calendar_container")){//唯一容器 var contain = $DC("div"); var s = contain.style; s.visibility = "hidden"; s.position = "absolute"; s.top = "0px";//不能占据页面空间 s.zIndex = 65530; contain.id = "calendar_container"; contain.innerHTML = this.toString(); document.body.appendChild(contain); if(isIE){ var ifm = $DC("iframe"); var s = ifm.style; ifm.frameBorder = 0; ifm.height = (contain.clientHeight - 3) + "px"; s.visibility = "inherit"; s.filter = "alpha(opacity=0)"; s.position = "absolute"; s.top = "0px";//不能占据页面空间 s.width = $("calendar_container").offsetWidth; s.zIndex = -1; contain.insertAdjacentElement("afterBegin",ifm); } } //覆盖日历事件 JCalendar.onupdate = function () {}; JCalendar.onclick = function (year,month,date){ $(JCalendar.cur_obj_id).value = $(JCalendar.cur_obj_id).value.replace(/^[^\s]*/i,year + '-' + month + '-' + date); hide("calendar_container"); } //邦定事件 document.attachEvent("onclick",function(){ if($("calendar_container").style.visibility="visible")hide("calendar_container"); }); obj.attachEvent("onclick",function(e){ var obj = e.srcElement; var dates =obj.value.split(/\s/)[0].split("-");//文本框日期数组,文本框内容可能有时间这样的字串,即:2007-5-26 15:39 var left = obj.offsetLeft , top = obj.offsetTop; var x,y,left,top; var contain = $("calendar_container"); var body = isDTD ? document.documentElement : document.body; left = body.scrollLeft + e.clientX - e.offsetX; top = body.scrollTop + e.clientY - e.offsetY; switch(direction){ case "right" : x = left + obj.offsetWidth; y = top;break; case "bottom" : x = left; y = top + obj.offsetHeight;break; } contain.style.top = y + "px"; contain.style.left = x + "px"; //更新日历日期 if(dates.length == 3 && (JCalendar.cur_year != dates[0] || JCalendar.cur_month != dates[1] || JCalendar.cur_date != dates[2])) JCalendar.update(dates[0],dates[1],dates[2]);//如果文本框有时间则更新时间到文本框的时间 else if (dates.length != 3){ var now = new Date(); JCalendar.update(now.getFullYear(),now.getMonth() + 1,now.getDate()); } if($("calendar_container").style.visibility="hidden")show("calendar_container"); e.cancelBubble = true; JCalendar.cur_obj_id = obj.id; }); $("calendar_container").attachEvent("onclick",function(e){e.cancelBubble = true;}); } /*===========================静态方法=======================================*/ /** *更新日历内容 */ JCalendar.update = function(_year,_month,_date){ date = new Date(_year,_month-1,1); var fday = date.getDay();//每月第一天的星期数 var year = date.getFullYear(); var month = date.getMonth() + 1; var dayNum = new Date(_year,_month,0).getDate();//每月的天数 var tds = $TN("td",$("calendar")); var years = $("select_year").options; var months = $("select_month").options; var _date = _date ? _date : JCalendar.cur_date; //更新当前年月 JCalendar.cur_year = year; JCalendar.cur_month = month; if(_date && _date <= dayNum) JCalendar.cur_date = _date; else if(_date > dayNum) JCalendar.cur_date = _date - dayNum; $("title_year").innerText = year + "年"; $("title_month").innerText = month + "月"; //更新年份下拉菜单选中项 for(var i = years.length - 1; i >= 0; i-- ){ if(years[i].value == year){ $("select_year").selectedIndex = i; break; } } //更新月份下拉菜单选中项 for(var i = months.length - 1; i >= 0; i-- ){ if(months[i].value == month){ $("select_month").selectedIndex = i; break; } } //清空日历内容,忽略日历头,即第一行 for(var i = 7; i < tds.length; i++) tds[i].innerText = ""; if( $("c_today"))$("c_today").removeAttribute("id"); for(var j = 1; j <= dayNum; j++){ tds[6 + fday + j].innerText = j; if(j == JCalendar.cur_date) tds[6 + fday + j].id = "c_today"; } JCalendar.onupdate(year,month,JCalendar.cur_date); } JCalendar.click = function(obj){ var tmp = $("c_today"); if(tmp && tmp == obj){ JCalendar.onclick(JCalendar.cur_year,JCalendar.cur_month,JCalendar.cur_date); } else if(obj.innerText != ""){ if(tmp) tmp.removeAttribute("id"); JCalendar.cur_date = parseInt(obj.innerText); obj.id = "c_today"; JCalendar.onclick(JCalendar.cur_year,JCalendar.cur_month,JCalendar.cur_date); } } JCalendar.over = function(obj){ if(obj.innerText != "") obj.className = "over"; } JCalendar.out = function(obj){ if(obj.innerText != "") obj.className = ""; } //日历更改时执行的函数,可以更改为自己需要函数,控件传递过来的参数为当前日期 JCalendar.onupdate = function(year,month,date){ alert("日历已更改,当前日历日期:" + year + "年" + month + "月" + date + "日"); } //点击日期时执行的函数,可以更改为自己需要函数,控件传递过来的参数为当前日期 JCalendar.onclick = function(year,month,date){ alert( "当前触发的日期:" + year + "年" + month + "月" + date + "日"); } </script> <script type="text/javascript" defer="defer"> ///////////////调用例子,作为输入控件//////////////// window.onload = function(){ var j = new JCalendar(); j.setYears(1990,2020); j.bind('a',"bottom"); j.bind('b'); } </script> </head> <body> <p class="center"> <input name="a" type="text" id="a" title="日历在俺下面" /> <input name="b" type="text" id="b" value="1990-1-1" title="日历在俺右边" /> </p> <p class="center"> <select> <option>看你能不能挡住我</option> </select> </p> <p class="center"> </p> <p class="center"> </p> <p class="center"> </p> <p class="center"> </p> </body> </html> |
特效说明: |
接口说明 一、JCalendar构造函数 参数: 1、三个表示年月日的整数,比如:new JCalendar(2007-5-18) 2、一个表示年月日的字串,年月日之间以“-”隔开,比如new JCalendar("2007-5-18") 3、空。参数为空,日历初始化为当前日期。
二、实例方法 1、toString() 得到解释后的日历的HTML代码 参数:无 返回:解释后的日历的HTML代码
2、setYears(first,last) 设置日历年份下拉菜单的年份范围 参数: 1、first 第一个年份界限 2、last 第二个年份界限 两个参数顺序可以颠倒
3、bind(obj_id,direction) 将日历邦定到某个文框,当点击该文本框的时候弹出日历。 日历的当前日期为文本框里的日期,如果文本框里有日期的话。否则就是当前日期 参数: 1、obj_id:文本框的id 2、direction:控制日历显示的方向,[right|bottom]。可以为空,默认为right。 right-日历显示在文本框的右边,bottom日历显示在文本框下面。
4、setKeyDate(Date_Array) 特别显示关键天,典型例子:博客、网络日志之类的日历 实现原理,为每个关键天的表格单元添加一个class,名字为keydate,CSS样式需要自己写,比如加个背景之类的 参数: Date_Array:日期的数组,比如:[1,4,6,9]
三、静态方法 多数静态方法是控件内部调用的,用户不应该调用。 但是有两个方法用户可以覆盖,也是日历为用户提供的两个事件: 1、JCalendar.onupdate:在日历日期更新时触发,用户需要自己写函数覆盖默认函数 2、JCalendar.onclick:在日历日期被点击时触发,用户需要自己写函数覆盖默认函数。 [注意]用作文本框输入控件时,不要覆盖。
当然,用户可以自己定义自己的日历样式,下面是样式的说明,同时也给出了本人的写的样式: #calendar_container {/ *日历容器,是一个绝对定位的DIV,在日历作为输入控件时才有用。作为文本框输入控件时必须定义这个样式,而且一定要定义宽度 */ width:160px; border:1px solid #06C; } #calendar {/*日历表格样式,对应的是一个<table>标签*/ border-collapse:collapse; background-color:#FFF; width:160px; height:120px; margin:0px auto; cursor:default; } #calendar td {/*很明显,这是一个表格单元*/ text-align:center; vertical-align:middle; font-family:"宋体"; } #calendar thead {/*表格头,也就是显示日一二三四五六那行*/ background-color:#999; color:#FFF; } #calendar caption {/*表格标题,也就是日历的第一行,显示年月的地方*/ background-color:#06C; } #calendar a{/*超链接样式*/ color:#F90; margin:0 5px; text-decoration:none; } #calendar #prev_month,#calendar #next_month {/*点击到上一个月,下一个月的两个箭头*/ font-size:18px; margin:0; } #calendar #c_today {/*表格单元格当前天的样式*/ background-color:#036; color:#FFF; } #calendar .over {/*鼠标经过单元格时,显示样式*/ background-color:#CCC; } #calendar .keydate {/*关键天显示样式*/ color:#06F; }
使用说明 例子一:文本框输入控件 1、实例化JCalendar 2、调用JCalendar的实例方法bind邦定文本框,其中可以多次调用bind方法进行邦定多个文本框。 3、调用例子: window.onload = function(){ var j = new JCalendar(); j.setYears(1990,2020);//设置年份下拉菜单范围为1990年到2020年 j.bind('a',"bottom"); j.bind('b'); }
例子二:网站页面普通的日历 1、实例化JCalendar 2、根据需要调用实例方法setKeyDate来设置关键天的显示,前提是定义好CSS样式,别忘了,样式是一个类,类名叫keydate 3、调用例子: window.onload = function(){ var j = new JCalendar(); j.setYears(1990,2020);//设置年份下拉菜单范围为1990年到2020年 document.getElementById("calendar_container").innerHTML = j.toString(); j.setKeyDate([1,4,7,14,23,28]);//设置关键天 } [注意]同一个页面,不能也不会出现两个以上实例(因为程序限制了^_^),即不能同时作为普通日历和输入控件用。 主要原因是用到了很多静态方法。
|
|
上一篇文章: 支持快捷键的javascript日期控件下一篇文章: 站长统计中使用的js日历控件 |
|
|