在開始之前我們先複習一下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日曆可以寫得很簡單,也可以弄得很複雜。作爲起步,我們先實現當前月的顯示,然後再一點點改進。(其實我就不明白,分明是一個個月顯示的,爲什麼不叫月曆,而叫日曆?!)
我們先觀察左邊這個樣板,日曆通常是分爲三部分,最上方是年份與星期數,中間是按一定規則排列的天數,最下方是按鈕,當然這幅圖缺了這個。一般而言,難點就是中間部分。我們要確定當月的第一天是星期幾,要與上方的星期數對應,然後一個接一個向下排。而放置天數的方法,一般都是塞在一個表格中,需要嵌套循環來分別生成tr與td。爲此,我想到另一個方法,把天數放置a元素中,利用液體佈局的方式讓它們自然地從左到右從上到下排列在一個div中。這樣做個好處,就是hover樣式是css原生的,不需要我們通過js的mouseover事件來綁定。爲了塞滿div,並分行顯示,我們需要指定a元素的display爲block,這樣它的寬與高才能生效,但這樣一行只能有一個a元素,因此我們還得指定其向左浮動,並限制div的寬與高,這樣元素就按照我們的想法排序了。爲了防止元素溢出,我們同時得把其容器也浮動。
現在的問題怎樣設置這些元素的內容,日曆上面的空間並不都有數字的。首先我們得知道當前月第一天是星期幾,因爲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 =
'<TT class=ybn onclick="preyear('
+args+
')"><<</TT>'
,
premonth =
'<TT class=mbn onclick="premonth('
+args+
')"><</TT>'
,
nextmonth =
'<TT class=mbn onclick="nextmonth('
+args+
')">></TT>'
,
nextyear =
'<TT class=ybn onclick="nextyear('
+args+
')">>></TT>'
,
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();
}
var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return
destination; } var Jcalendar = Class.create(); Jcalendar.prototype = { initialize:function(options){ this.setOptions(options); var $ = new Date(); this.drawCalendar($.getFullYear(),$.getMonth() + 1,$.getDate()); }, setOptions: function(options) { this.options
= {//默認屬性集中寫在這裏。 id:'jcalendar_'+ new Date().getTime(), text_id:null,//用於輸入日期的文本域的ID parent_id:null//指定父節點 }; extend(this.options, options || {}); }, ID:function(id){ return document.getElementById(id) }, TN:function(tn){ return document.getElementsByTagName(tn)
}, CE:function(s){ return document.createElement(s) }, getHandle:function(){ return this.ID(this.options.id); }, fillArray : function(year,month){//fill Array 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; }, addToDom:function(calendar){//add to dom tree var parent = this.ID(this.options.parent_id) || this.TN('body')[0];
parent.insertBefore(calendar,null); }, drawCalendar : function(year,month,date){ (month < 1) &&(year--,month = 12) ; (month > 12)&&(year++,month = 1) ; var $ = this,T='getElementsByTagName', calendar = $.getHandle(),//日曆的容器 weeks = "日一二三四五六".split(''),//日曆第二行的內容,顯示星期幾
arr = $.fillArray(year,month),//保存當月的日期 text_id = $.options.text_id;//用於輸入日期的文本域的ID if(calendar) { calendar.innerHTML = ''; }else{ calendar = $.CE('div'); $.addToDom(calendar);//把日曆加入DOM樹中 calendar.setAttribute('id', $.options.id);//設置ID } calendar.innerHTML+=
'<< <'+ year+'年'+month+'月'+date +'日> >>'; for(var i = 0;i <7;i++){ calendar.innerHTML += ''+weeks[i]+''; } for(i = 0;i <42;i++){ calendar.innerHTML += (!arr[i]) ? '
' :(''+arr[i].split('-')[2]+'') } var tts = calendar[T]("tt"); tts[0].onclick = function(){ $.drawCalendar(year-1,month,date);
} tts[1].onclick = function(){ $.drawCalendar(year,month-1,date); } tts[2].onclick = function(){ $.drawCalendar(year,month+1,date); } tts[3].onclick = function(){ $.drawCalendar(year+1,month,date); } var dates = calendar[T]("kbd"),j = dates.length; while (--j
>= 0) { dates[j].onclick = function(){ this.parentNode.style.backgroundColor = "#D2F9DF"; } } } } ; var indigene = document.getElementById("Calendar1_entryCal"); indigene.style.display = "none"; var div = document.createElement("div"); indigene.parentNode.insertBefore(div,indigene);
div.setAttribute("id","jcalendar_parent"); new Jcalendar({ id:'jcalendar', parent_id:'jcalendar_parent' });
上面的按鈕的顯示符號應該是<與>,而不是單純的小於號或大於號,這是高亮插件的緣故……另,這個日曆改一改,就可以成爲彈出式日期選擇器了!至於它,下次有次再說!