最终效果可参见左边栏的日历(注,一定要在非IE下才可以浏览到,因为我还没有完全突破博客园的脚本封锁。在非IE游览器中,原日历被我hack掉,换成我的日历,可点击箭头选择年份与月份,日期上有悬浮效果与点击变色效果!)
在开始之前我们先复习一下javascript的Date对象,这是一个内置对象,它包含了一系列方法供我们操作。按功能可以分为以下三大类:
获得时间方法:
- getDate() 查看Date对象并返回日期
- getDay() 返回星期几
- getHours() 返回小时数
- getMinutes() 返回分钟数
- getMonth() 返回月份值
- getSeconds() 返回秒数
- getMilliseconds()返回毫秒值
- getTime() 返回完整的时间
- getYear() 返回年份
- getFullYear()返回一个四位数表示的年份
- getTimezoneOffset() 返回本地时间和GMT相差的分钟数
注:用getYear()返回的数并不一定是4位的!处于1900年和1999年间的getYear()方法返回的只有两位数。在此之前的或是在此之后的年份返回的都是四位数的。getYear()方法不应该再使用了。推荐使用getFullYear方法。另,javascript也提系列基于世界时的时间设置函数,如 getUTCDate(),getUTCDay(),getUTCFullYear(),getUTCHours(),getUTCMilliSeconds(),getUTCMinutes(),getUTCMonth ()与getUTCSeconds()方法。
1./********根据一个日期求得星期,如'2009-6-21' return 0(星期日)***********/2.var get_day = function (strDate){ 3. var f = strDate.replace(/-/g,'/'); 4. f = new Date(f).getDay(); 5. return "星期"+"天一二三四五六".split('')[f] 6.} 7.alert(get_day('2009-7-25'))设置时间方法:
- setDate() 改变Date对象的日期
- setYear() 改变年份
- setMonth() 改变月份
- setHours() 改变小时数
- setMinutes() 改变分钟数
- setSeconds() 改变秒数
- setTime() 改变完整的时间
注,由于javascript是从0开始的,因此需要对月份进行操作时要加1 .
| 参数 | 描述 |
|---|---|
| month | 必需。一个表示月份的数值,该值介于 0(一月) ~ 11(十二月) 之间。 |
| day | 可选。一个表示月的某一天的数值,该值介于 1 ~ 31 之间(以本地时间计)。在 EMCAScript 标准化之前,不支持该参数。 |
1.var now = new Date() 2.var currentMonth = now.getMonth() -1 //获得当前的月份 3.var nextMonth = now.getMonth() //获得下一个月的月份1.//用javascript取得某一年的第一个星期一的日期 2.function get(year) { 3. var d = new Date(year, 1, 1); 4. var day = d.getDay(); //获取1月1号是星期几 5. d.setDate((8 - day) % 7 + 1); 6. return d; 7.}01.//求前 n 天或者后 n 天的日期(用xxxx-xx-xx表示) 02.var showdate = function(n){ 03. var d = new Date(); 04. d.setDate(d.getDate()+n); 05. //或者 d = d.getFullYear() + "-" + (d.getMonth()+1) + "-" + d.getDate(); 06. d = d.toLocaleDateString().replace(/[\u4e00-\u9fa5]/g,'-').replace(/-$/,'') 07. return d; 08.} 09.alert("今天是:"+showdate(0)); 10.alert("昨天是:"+showdate(-1)); 11.alert("明天是:"+showdate(1)); 12.alert("10天前是:"+showdate(-10)); 13.alert("8天后是:"+showdate(8));1.//将2005-8-5转换成2005-08-05格式 2.var strDate = '2005-8-5'; 3.window.alert(strDate.replace(/\b(\w)\b/g, '0$1'));01.// 对Date的扩展,将 Date 转化为指定格式的String 02.// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, 03.// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) 04.// 例子: 05.// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 06.// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 07.Date.prototype.Format = function(fmt) { //@author: meizz 08. var o = { 09. "M+" : this.getMonth()+1, //月份 10. "d+" : this.getDate(), //日 11. "h+" : this.getHours(), //小时 12. "m+" : this.getMinutes(), //分 13. "s+" : this.getSeconds(), //秒 14. "q+" : Math.floor((this.getMonth()+3)/3), //季度 15. "S" : this.getMilliseconds() //毫秒 16. }; 17. if(/(y+)/.test(fmt)) 18. fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); 19. for(var k in o) 20. if(new RegExp("("+ k +")").test(fmt)) 21. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length))); 22. return fmt; 23.}转换时间方法:
- toGMTString() 把Date对象的日期(一个数值)转变成一个GMT时间字符串,返回类似下面的值:Weds,15 June l997 14:02:02 GMT(精确的格式依赖于计算机上所运行的操作系统而变)
- toLocaleString() 把Date对象的日期(一个数值)转变成一个字符串,使用所在计算机上配置使用的特定日期格式
- UTC() 使用Date UTC(年、月、日、时、分、秒),以自从1970年1月1日00:00:00(其中时、分、秒是可选的)以来的毫秒数的形式返回
- toLocaleDateString() 方法可根据本地时间把 Date 对象的日期部分转换为字符串,并返回结果
- toLocaleTimeString() 方法可根据本地时间把 Date 对象的时间部分转换为字符串,并返回结果
仅显示当前月的日历
javascript日历可以写得很简单,也可以弄得很复杂。作为起步,我们先实现当前月的显示,然后再一点点改进。(其实我就不明白,分明是一个个月显示的,为什么不叫月历,而叫日历?!)
我们先观察左边这个样板,日历通常是分为三部分,最上方是年份与星期数,中间是按一定规则排列的天数,最下方是按钮,当然这幅图缺了这个。一般而言,难点就是中间部分。我们要确定当月的第一天是星期几,要与上方的星期数对应,然后一个接一个向下排。而放置天数的方法,一般都是塞在一个表格中,需要嵌套循环来分别生成tr与td。为此,我想到另一个方法,把天数放置a元素中,利用液体布局的方式让它们自然地从左到右从上到下排列在一个div中。这样做个好处,就是hover样式是css原生的,不需要我们通过js的mouseover事件来绑定。为了塞满div,并分行显示,我们需要指定a元素的display为block,这样它的宽与高才能生效,但这样一行只能有一个a元素,因此我们还得指定其向左浮动,并限制div的宽与高,这样元素就按照我们的想法排序了。为了防止元素溢出,我们同时得把其容器也浮动。现在的问题怎样设置这些元素的内容,日历上面的空间并不都有数字的。首先我们得知道当前月第一天是星期几,因为js会把星期几转化为我们日历的第一行的数字;然后的问题是这个月有几天。我们先做个测试,把数组填空了再说!
01.window.onload = function(){ 02. //*********************第一阶段,填空日期数组******************* 03. var now = new Date(), 04. date = now.getDate(),//当前天数 05. month = now.getMonth() + 1,//当前的月份 06. year = now.getFullYear(),//当前的年份 07. firstday = new Date(now.getFullYear(), month -1 ,1).getDay(), //求出当月的第一天是星期几 08. lastday = new Date(now.getFullYear(), month , 0).getDate(),//上月的第0天就是今月的最后一天 09. dates = lastday,//最后一天的号数就是这个月的天数 10. arr = new Array(42);//用来装载日期的数组,日期以‘xxxx-xx-xx’的形式表示 11. for(var i = 0,j = firstday; i < dates ; i ++ ,j ++){ 12. arr[j] = year +'-'+ month +'-'+ (i+1) ; 13. } 14. /***********************以下是测试部分**********************/ 15. for(var i = 0;i <42;i++){ 16. document.write(arr[i]+' ');//打印测试结果 17. } 18.}接着下来我们就可以绘制UI了,我们用一个DIV来代表日历本身,头部由填满一行的span表示(也就是把span的display设为block),紧接着是星期数,它们都是a元素,下面是日期数,也是a元素。我们需要区分a元素的样式,让表示星期数的带上一个class来特别设置。样式我们暂时放弃动态生成。
01.<!doctype html> 02.<html dir="ltr" lang="zh-CN"> 03. <head> 04. <meta charset="utf-8"/> 05. <meta http-equiv="X-UA-Compatible" content="IE=Edge"> 06. <title>跨游览器的JS日历</title> 07. <style type="text/css"> 08. #jcalendar { 09. width:210px; 10. background:#E0ECF9; 11. border:1px solid #479AC7; 12. float:left; 13. } 14. #jcalendar span { 15. float:left; 16. width:210px; 17. height:20px; 18. background:#479AC7; 19. color:#f90; 20. font-weight:bolder; 21. text-align:center; 22. } 23. #jcalendar .week { 24. background:#D5F3F4; 25. color:#808080; 26. } 27. #jcalendar .current{ 28. background:#336699; 29. color:#fff; 30. } 31. #jcalendar a { 32. display:block; 33. float:left; 34. width:30px; 35. height:20px; 36. color:#000; 37. line-height:20px; 38. text-align:center; 39. text-decoration:none; 40. } 41. 42. </style> 43. <script type="text/javascript"> 44. </script> 45. </head> 46. <body> 47. </body> 48.</html>01.window.onload = function(){ 02. //*********************第一阶段,填空日期数组******************* 03. //***************************略************************** 04. //**********************第二阶段,绘制UI****************** 05. var body = document.getElementsByTagName('body')[0],//body的快捷引用 06. a = document.createElement('a'),//日历的a元素,用于克隆 07. calendar = document.createElement('div'),//日历的容器元素 08. thead = document.createElement('span');//日历的头部或页眉 09. body.insertBefore(calendar,null);//把日历加入DOM树中 10. calendar.setAttribute('id','jcalendar'); 11. thead.innerHTML = year +"年 " + month +"月"12. calendar.appendChild(thead); 13. var weeks = "日一二三四五六".split('');//日历第二行的内容,显示星期几 14. for(i = 0;i< 7;i++){ 15. var th = a.cloneNode(); 16. th.innerHTML = weeks[i]; 17. th.className = 'week'; 18. calendar.appendChild(th); 19. } 20. for(i = 0;i <42;i++){ 21. var td = a.cloneNode(); 22. if(arr[i] == undefined ){ 23. calendar.appendChild(td); 24. }else{ 25. var html = arr[i].split('-')[2]; 26. td.innerHTML = html; 27. if(html == date){ 28. td.className = 'current'; 29. } 30. calendar.appendChild(td); 31. } 32. } 33.}好了,静态的日历就做出来了,现在我们加入动态元素,在头部添加四个按钮,让它选择上一月,下一月,上一年与下一年。由于我们的日历是基于那个填空数组,而填空数组是是基于年份与月份,因此年份与月份一改变,我们就不可避免地重绘整个日历。我们把重绘日历的逻辑独立出来做成一个函数,好让按钮上的函数去调用它!并在日期上添加悬浮效果与单击事件。
添加新样式
01.#jcalendar .ybn { 02. color:#000; 03.} 04.#jcalendar .mbn { 05. color:#000040; 06.} 07.#jcalendar .weekend { 08. color:#f00!important; 09.} 10.#jcalendar a.day:hover{ 11. background:#99C3F6; 12.}javascript修改为:
01.var fillArray = function(year,month){ 02. var firstday = new Date(year, month -1 ,1).getDay(), //求出当月的第一天是星期几 03. lastday = new Date(year, month , 0).getDate(),//上个月的第零天就是今个月的最后一天 04. dates = lastday,//最后一天的号数就是这个月的天数 05. arr = new Array(42);//用来装载日期的数组,日期以‘xxxx-xx-xx’的形式表示 06. for(var i = 0,j = firstday; i < dates ; i ++ ,j ++){ 07. arr[j] = year +'-'+ month +'-'+ (i+1) ; 08. } 09. return arr; 10.} 11.var nextmonth = function(year,month,date){//按钮事件1 12. month = month + 1; 13. if(month > 12) year = year +1,month = 1; 14. var arr = fillArray(year,month); 15. drawCalendar(arr,year,month,date); 16.} 17.var nextyear = function(year,month,date){//按钮事件2 18. year = year + 1; 19. var arr = fillArray(year,month); 20. drawCalendar(arr,year,month,date); 21.} 22.var premonth = function(year,month,date){//按钮事件3 23. month = month - 1; 24. if(month < 1) year = year -1,month =12; 25. var arr = fillArray(year,month); 26. drawCalendar(arr,year,month,date); 27.} 28.var preyear = function(year,month,date){//按钮事件4 29. year = year - 1; 30. var arr = fillArray(year,month); 31. drawCalendar(arr,year,month,date); 32.} 33.var drawCalendar = function(arr,year,month,date){ 34. var _calendar = document.getElementById("jcalendar"); 35. if(_calendar) _calendar.parentNode.removeChild(_calendar); 36. 37. var body = document.getElementsByTagName('body')[0],//body的快捷引用 38. a = document.createElement('a'),//日历的a元素,用于克隆 39. calendar = document.createElement('div'),//日历的容器元素 40. thead = document.createElement('span');//日历的头部或页眉 41. body.insertBefore(calendar,null);//把日历加入DOM树中 42. calendar.setAttribute('id','jcalendar'); 43. var args = year+','+month+','+date, 44. preyear = '<TT class=ybn onclick="preyear('+args+')"><<</TT>', 45. premonth = '<TT class=mbn onclick="premonth('+args+')"><</TT>', 46. nextmonth = '<TT class=mbn onclick="nextmonth('+args+')">></TT>', 47. nextyear = '<TT class=ybn onclick="nextyear('+args+')">>></TT>', 48. str = new Date(args.replace(/,/g,'/')).toLocaleDateString(); 49. thead.innerHTML = preyear + ' '+premonth + ' '+str+' '+nextmonth + ' '+nextyear; 50. calendar.appendChild(thead); 51. var weeks = "日一二三四五六".split('');//日历第二行的内容,显示星期几 52. for(i = 0;i< 7;i++){ 53. var th = a.cloneNode(); 54. th.innerHTML = weeks[i]; 55. th.className = 'week'; 56. calendar.appendChild(th); 57. } 58. for(i = 0;i <42;i++){ 59. var td = a.cloneNode(); 60. if(arr[i] == undefined ){ 61. calendar.appendChild(td); 62. }else{ 63. var html = arr[i].split('-')[2]; 64. td.innerHTML = html; 65. td.className = 'day'; 66. td.href = "javascript:void(0)";//为ie6准备的 67. if(date && html == date){ 68. td.className = td.className +' current'; 69. } 70. if(i%7 == 0 || i%7 == 6){ 71. td.className = td.className +' weekend'; 72. } 73. td.onclick = (function(i){ 74. return function(){ 75. alert(i);//这里后面我们要修改,让arr[i]填空文本域 76. } 77. })(arr[i]); 78. calendar.appendChild(td); 79. } 80. } 81.} 82.window.onload = function(){ 83. //*********************第一阶段,填空日期数组******************* 84. var now = new Date(), 85. month = now.getMonth() + 1,//当前的月份 86. year = now.getFullYear(),//当前的年份 87. date = now.getDate(), 88. arr = fillArray(year,month); 89. //**********************第二阶段,绘制UI****************** 90. drawCalendar(arr,year,month,date); 91.}好了,该有的都有了,现在封装一下它吧。把上面四个按钮事件合并成一个,加个更见名达义的名称,然后统统塞到一个类中。
001.var Class = { 002. create: function() { 003. return function() { 004. this.initialize.apply(this, arguments); 005. } 006. } 007.} 008.//*********************Jcalendar类开始********************** 009.var Jcalendar = Class.create(); 010.Jcalendar.prototype = { 011. initialize:function(){ 012. var $ = new Date(); 013. this.drawCalendar($.getFullYear(),$.getMonth() + 1,$.getDate()); 014. }, 015. fillArray : function(year,month){ 016. var f = new Date(year, month -1 ,1).getDay(), //求出当月的第一天是星期几 017. dates = new Date(year, month , 0).getDate(),//上个月的第零天就是今个月的最后一天 018. arr = new Array(42);//用来装载日期的数组,日期以‘xxxx-xx-xx’的形式表示 019. for(var i = 0; i < dates ; i ++ ,f ++){ 020. arr[f] = year +'-'+ month +'-'+ (i+1) ; 021. } 022. return arr; 023. }, 024. drawCalendar : function(year,month,date){ 025. var $ = document,$$ = 'createElement', 026. _calendar = $.getElementById("jcalendar"); 027. if(_calendar) _calendar.parentNode.removeChild(_calendar);//推倒重绘! 028. var body = $.getElementsByTagName('body')[0],//body的快捷引用 029. weeks = "日一二三四五六".split(''),//日历第二行的内容,显示星期几 030. calendar = $[$$]('div'),//日历的容器元素 031. a = $[$$]('a'),//日历的a元素,用于克隆 032. tt = $[$$]("tt"),//日历页眉的tt元素,用于克隆 033. thead = $[$$]('span'),//日历页眉 034. fragment = $.createDocumentFragment(),//减少DOM刷新页面的次数 035. arr = this.fillArray(year,month),//保存当月的日期 036. tts = [],//用于保存tt元素的引用 037. ths = this;//用于保存Jcalendar对象的实例的引用 038. body.insertBefore(calendar,null);//把日历加入DOM树中 039. calendar.setAttribute('id','jcalendar'); 040. for(var i = 0;i<4;i++){//循环生成出个时间按钮。 041. var clone = tt.cloneNode(true);//比重新createElement快 042. clone.onclick = (function(index){ 043. return function(){//在闭包里绑定事件 044. ths.redrawCalendar(year,month,date,index) 045. } 046. })(i); 047. tts[i] = clone;//保存引用 048. if(i==2) thead.appendChild($.createTextNode(year+"年"+month+"月"+date+"日")); 049. thead.appendChild(clone); 050. } 051. tts[0].innerHTML = '<<'; 052. tts[1].innerHTML = '<'; 053. tts[2].innerHTML = '>'; 054. tts[3].innerHTML = '>>'; 055. tts[0].className = tts[3].className = 'mbn'; 056. tts[1].className = tts[2].className = 'ybn'; 057. fragment.appendChild(thead); 058. for(i = 0;i <7;i++){//星期显示区 059. var th = a.cloneNode(true); 060. th.innerHTML = weeks[i]; 061. th.className = 'week'; 062. fragment.appendChild(th); 063. } 064. for(i = 0;i <42;i++){//日期显示区 065. var td = a.cloneNode(true); 066. if(arr[i] == undefined ){ 067. fragment.appendChild(td); 068. }else{ 069. var html = arr[i].split('-')[2]; 070. td.innerHTML = html; 071. td.className = 'day'; 072. td.href = "javascript:void(0)";//为ie6准备的 073. (date && html == date)&&(td.className += ' current') ;//高亮每个月今天这一天 074. (i%7 == 0 || i%7 == 6)&&(td.className += ' weekend') ;//为周末添加多一个类 075. td.onclick = (function(i){ 076. return function(){ 077. alert(i); 078. } 079. })(arr[i]); 080. fragment.appendChild(td); 081. } 082. } 083. calendar.appendChild(fragment); 084. }, 085. 086. redrawCalendar : function(year,month,date,index){ 087. switch(index){ 088. case 0 ://preyear 089. year--; 090. break; 091. case 1://premonth 092. month--; 093. (month < 1) &&(year--,month = 12) ; 094. break; 095. case 2://nextmonth 096. month++; 097. (month > 12)&&(year++,month = 1) ; 098. break; 099. case 3://nextyear 100. year++; 101. break; 102. } 103. this.drawCalendar(year,month,date); 104. } 105.} 106.//*********************Jcalendar类结束********************** 107.window.onload = function(){ 108. new Jcalendar(); 109.}上面的按钮的显示符号应该是<与>,而不是单纯的小于号或大于号,这是高亮插件的缘故……另,这个日历改一改,就可以成为弹出式日期选择器了!至于它,下次有次再说!
浙公网安备 33010602011771号