最终效果可参见左边栏的日历。原日历被我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()方法。
/********根据一个日期求得星期,如'2009-6-21' return 0(星期日)***********/
var get_day = function (strDate){
var f = strDate.replace(/-/g,'/');
f = new Date(f).getDay();
return "星期"+"天一二三四五六".split('')[f]
}
alert(get_day('2009-7-25'))
设置时间方法:
- setDate() 改变Date对象的日期
- setYear() 改变年份
- setMonth() 改变月份
- setHours() 改变小时数
- setMinutes() 改变分钟数
- setSeconds() 改变秒数
- setTime() 改变完整的时间
注,由于javascript是从0开始的,因此需要对月份进行操作时要加1 .
参数 | 描述 |
---|---|
month | 必需。一个表示月份的数值,该值介于 0(一月) ~ 11(十二月) 之间。 |
day | 可选。一个表示月的某一天的数值,该值介于 1 ~ 31 之间(以本地时间计)。在 EMCAScript 标准化之前,不支持该参数。 |
var now = new Date()
var currentMonth = now.getMonth() -1 //获得当前的月份
var nextMonth = now.getMonth() //获得下一个月的月份
//用javascript取得某一年的第一个星期一的日期
function get(year) {
var d = new Date(year, 1, 1);
var day = d.getDay(); //获取1月1号是星期几
d.setDate((8 - day) % 7 + 1);
return d;
}
//求前 n 天或者后 n 天的日期(用xxxx-xx-xx表示)
var showdate = function(n){
var d = new Date();
d.setDate(d.getDate()+n);
//或者 d = d.getFullYear() + "-" + (d.getMonth()+1) + "-" + d.getDate();
d = d.toLocaleDateString().replace(/[/u4e00-/u9fa5]/g,'-').replace(/-$/,'')
return d;
}
alert("今天是:"+showdate(0));
alert("昨天是:"+showdate(-1));
alert("明天是:"+showdate(1));
alert("10天前是:"+showdate(-10));
alert("8天后是:"+showdate(8));
//将2005-8-5转换成2005-08-05格式
var strDate = '2005-8-5';
window.alert(strDate.replace(//b(/w)/b/g, '0$1'));
// 对Date的扩展,将 Date 转化为指定格式的String
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
// 例子:
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
Date.prototype.Format = function(fmt) { //@author: meizz
var o = {
"M+" : this.getMonth()+1, //月份
"d+" : this.getDate(), //日
"h+" : this.getHours(), //小时
"m+" : this.getMinutes(), //分
"s+" : this.getSeconds(), //秒
"q+" : Math.floor((this.getMonth()+3)/3), //季度
"S" : this.getMilliseconds() //毫秒
};
if(/(y+)/.test(fmt))
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
for(var k in o)
if(new RegExp("("+ k +")").test(fmt))
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
return fmt;
}
转换时间方法:
- 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日历可以写得很简单,也可以弄得很复杂。作为起步,我们先实现当前月的显示,然后再一点点改进。(其实我就不明白,分明是一个个月显示的,为什么不叫月历,而叫日历?!)

现在的问题怎样设置这些元素的内容,日历上面的空间并不都有数字的。首先我们得知道当前月第一天是星期几,因为js会把星期几转化为我们日历的第一行的数字;然后的问题是这个月有几天。我们先做个测试,把数组填空了再说!
window.onload = function(){
//*********************第一阶段,填空日期数组*******************
var now = new Date(),
date = now.getDate(),//当前天数
month = now.getMonth() + 1,//当前的月份
year = now.getFullYear(),//当前的年份
firstday = new Date(now.getFullYear(), month -1 ,1).getDay(), //求出当月的第一天是星期几
lastday = new Date(now.getFullYear(), month , 0).getDate(),//上月的第0天就是今月的最后一天
dates = lastday,//最后一天的号数就是这个月的天数
arr = new Array(42);//用来装载日期的数组,日期以‘xxxx-xx-xx’的形式表示
for(var i = 0,j = firstday; i < dates ; i ++ ,j ++){
arr[j] = year +'-'+ month +'-'+ (i+1) ;
}
/***********************以下是测试部分**********************/
for(var i = 0;i <42;i++){
document.write(arr[i]+' ');//打印测试结果
}
}
接着下来我们就可以绘制UI了,我们用一个DIV来代表日历本身,头部由填满一行的span表示(也就是把span的display设为block),紧接着是星期数,它们都是a元素,下面是日期数,也是a元素。我们需要区分a元素的样式,让表示星期数的带上一个class来特别设置。样式我们暂时放弃动态生成。
<!doctype html>
<html dir="ltr" lang="zh-CN">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>跨游览器的JS日历</title>
<style type="text/css">
#jcalendar {
width:210px;
background:#E0ECF9;
border:1px solid #479AC7;
float:left;
}
#jcalendar span {
float:left;
width:210px;
height:20px;
background:#479AC7;
color:#f90;
font-weight:bolder;
text-align:center;
}
#jcalendar .week {
background:#D5F3F4;
color:#808080;
}
#jcalendar .current{
background:#336699;
color:#fff;
}
#jcalendar a {
display:block;
float:left;
width:30px;
height:20px;
color:#000;
line-height:20px;
text-align:center;
text-decoration:none;
}
</style>
<script type="text/javascript">
</script>
</head>
<body>
</body>
</html>
window.onload = function(){
//*********************第一阶段,填空日期数组*******************
//***************************略**************************
//**********************第二阶段,绘制UI******************
var body = document.getElementsByTagName('body')[0],//body的快捷引用
a = document.createElement('a'),//日历的a元素,用于克隆
calendar = document.createElement('div'),//日历的容器元素
thead = document.createElement('span');//日历的头部或页眉
body.insertBefore(calendar,null);//把日历加入DOM树中
calendar.setAttribute('id','jcalendar');
thead.innerHTML = year +"年 " + month +"月"
calendar.appendChild(thead);
var weeks = "日一二三四五六".split('');//日历第二行的内容,显示星期几
for(i = 0;i< 7;i++){
var th = a.cloneNode();
th.innerHTML = weeks[i];
th.className = 'week';
calendar.appendChild(th);
}
for(i = 0;i <42;i++){
var td = a.cloneNode();
if(arr[i] == undefined ){
calendar.appendChild(td);
}else{
var html = arr[i].split('-')[2];
td.innerHTML = html;
if(html == date){
td.className = 'current';
}
calendar.appendChild(td);
}
}
}
好了,静态的日历就做出来了,现在我们加入动态元素,在头部添加四个按钮,让它选择上一月,下一月,上一年与下一年。由于我们的日历是基于那个填空数组,而填空数组是是基于年份与月份,因此年份与月份一改变,我们就不可避免地重绘整个日历。我们把重绘日历的逻辑独立出来做成一个函数,好让按钮上的函数去调用它!并在日期上添加悬浮效果与单击事件。
添加新样式
#jcalendar .ybn {
color:#000;
}
#jcalendar .mbn {
color:#000040;
}
#jcalendar .weekend {
color:#f00!important;
}
#jcalendar a.day:hover{
background:#99C3F6;
}
javascript修改为:
var fillArray = function(year,month){
var firstday = new Date(year, month -1 ,1).getDay(), //求出当月的第一天是星期几
lastday = new Date(year, month , 0).getDate(),//上个月的第零天就是今个月的最后一天
dates = lastday,//最后一天的号数就是这个月的天数
arr = new Array(42);//用来装载日期的数组,日期以‘xxxx-xx-xx’的形式表示
for(var i = 0,j = firstday; i < dates ; i ++ ,j ++){
arr[j] = year +'-'+ month +'-'+ (i+1) ;
}
return arr;
}
var nextmonth = function(year,month,date){//按钮事件1
month = month + 1;
if(month > 12) year = year +1,month = 1;
var arr = fillArray(year,month);
drawCalendar(arr,year,month,date);
}
var nextyear = function(year,month,date){//按钮事件2
year = year + 1;
var arr = fillArray(year,month);
drawCalendar(arr,year,month,date);
}
var premonth = function(year,month,date){//按钮事件3
month = month - 1;
if(month < 1) year = year -1,month =12;
var arr = fillArray(year,month);
drawCalendar(arr,year,month,date);
}
var preyear = function(year,month,date){//按钮事件4
year = year - 1;
var arr = fillArray(year,month);
drawCalendar(arr,year,month,date);
}
var drawCalendar = function(arr,year,month,date){
var _calendar = document.getElementById("jcalendar");
if(_calendar) _calendar.parentNode.removeChild(_calendar);
var body = document.getElementsByTagName('body')[0],//body的快捷引用
a = document.createElement('a'),//日历的a元素,用于克隆
calendar = document.createElement('div'),//日历的容器元素
thead = document.createElement('span');//日历的头部或页眉
body.insertBefore(calendar,null);//把日历加入DOM树中
calendar.setAttribute('id','jcalendar');
var args = year+','+month+','+date,
preyear = '<<',
premonth = '<',
nextmonth = '>',
nextyear = '>>',
str = new Date(args.replace(/,/g,'/')).toLocaleDateString();
thead.innerHTML = preyear + ' '+premonth + ' '+str+' '+nextmonth + ' '+nextyear;
calendar.appendChild(thead);
var weeks = "日一二三四五六".split('');//日历第二行的内容,显示星期几
for(i = 0;i< 7;i++){
var th = a.cloneNode();
th.innerHTML = weeks[i];
th.className = 'week';
calendar.appendChild(th);
}
for(i = 0;i <42;i++){
var td = a.cloneNode();
if(arr[i] == undefined ){
calendar.appendChild(td);
}else{
var html = arr[i].split('-')[2];
td.innerHTML = html;
td.className = 'day';
td.href = "javascript:void(0)";//为ie6准备的
if(date && html == date){
td.className = td.className +' current';
}
if(i%7 == 0 || i%7 == 6){
td.className = td.className +' weekend';
}
td.onclick = (function(i){
return function(){
alert(i);//这里后面我们要修改,让arr[i]填空文本域
}
})(arr[i]);
calendar.appendChild(td);
}
}
}
window.onload = function(){
//*********************第一阶段,填空日期数组*******************
var now = new Date(),
month = now.getMonth() + 1,//当前的月份
year = now.getFullYear(),//当前的年份
date = now.getDate(),
arr = fillArray(year,month);
//**********************第二阶段,绘制UI******************
drawCalendar(arr,year,month,date);
}
好了,该有的都有了,现在封装一下它吧。把上面四个按钮事件合并成一个,加个更见名达义的名称,然后统统塞到一个类中。
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
//*********************Jcalendar类开始**********************
var Jcalendar = Class.create();
Jcalendar.prototype = {
initialize:function(){
var $ = new Date();
this.drawCalendar($.getFullYear(),$.getMonth() + 1,$.getDate());
},
fillArray : function(year,month){
var f = new Date(year, month -1 ,1).getDay(), //求出当月的第一天是星期几
dates = new Date(year, month , 0).getDate(),//上个月的第零天就是今个月的最后一天
arr = new Array(42);//用来装载日期的数组,日期以‘xxxx-xx-xx’的形式表示
for(var i = 0; i < dates ; i ++ ,f ++){
arr[f] = year +'-'+ month +'-'+ (i+1) ;
}
return arr;
},
drawCalendar : function(year,month,date){
var $ = document,$$ = 'createElement',
_calendar = $.getElementById("jcalendar");
if(_calendar) _calendar.parentNode.removeChild(_calendar);//推倒重绘!
var body = $.getElementsByTagName('body')[0],//body的快捷引用
weeks = "日一二三四五六".split(''),//日历第二行的内容,显示星期几
calendar = $[$$]('div'),//日历的容器元素
a = $[$$]('a'),//日历的a元素,用于克隆
tt = $[$$]("tt"),//日历页眉的tt元素,用于克隆
thead = $[$$]('span'),//日历页眉
fragment = $.createDocumentFragment(),//减少DOM刷新页面的次数
arr = this.fillArray(year,month),//保存当月的日期
tts = [],//用于保存tt元素的引用
ths = this;//用于保存Jcalendar对象的实例的引用
body.insertBefore(calendar,null);//把日历加入DOM树中
calendar.setAttribute('id','jcalendar');
for(var i = 0;i<4;i++){//循环生成出个时间按钮。
var clone = tt.cloneNode(true);//比重新createElement快
clone.onclick = (function(index){
return function(){//在闭包里绑定事件
ths.redrawCalendar(year,month,date,index)
}
})(i);
tts[i] = clone;//保存引用
if(i==2) thead.appendChild($.createTextNode(year+"年"+month+"月"+date+"日"));
thead.appendChild(clone);
}
tts[0].innerHTML = '<<';
tts[1].innerHTML = '<';
tts[2].innerHTML = '>';
tts[3].innerHTML = '>>';
tts[0].className = tts[3].className = 'mbn';
tts[1].className = tts[2].className = 'ybn';
fragment.appendChild(thead);
for(i = 0;i <7;i++){//星期显示区
var th = a.cloneNode(true);
th.innerHTML = weeks[i];
th.className = 'week';
fragment.appendChild(th);
}
for(i = 0;i <42;i++){//日期显示区
var td = a.cloneNode(true);
if(arr[i] == undefined ){
fragment.appendChild(td);
}else{
var html = arr[i].split('-')[2];
td.innerHTML = html;
td.className = 'day';
td.href = "javascript:void(0)";//为ie6准备的
(date && html == date)&&(td.className += ' current') ;//高亮每个月今天这一天
(i%7 == 0 || i%7 == 6)&&(td.className += ' weekend') ;//为周末添加多一个类
td.onclick = (function(i){
return function(){
alert(i);
}
})(arr[i]);
fragment.appendChild(td);
}
}
calendar.appendChild(fragment);
},
redrawCalendar : function(year,month,date,index){
switch(index){
case 0 ://preyear
year--;
break;
case 1://premonth
month--;
(month < 1) &&(year--,month = 12) ;
break;
case 2://nextmonth
month++;
(month > 12)&&(year++,month = 1) ;
break;
case 3://nextyear
year++;
break;
}
this.drawCalendar(year,month,date);
}
}
//*********************Jcalendar类结束**********************
window.onload = function(){
new Jcalendar();
}
上面的按钮的显示符号应该是<与>,而不是单纯的小于号或大于号,这是高亮插件的缘故……另,这个日历改一改,就可以成为弹出式日期选择器了!至于它,下次有空再说!
PS:回复功能已修复!!!