JS學習之一個簡易的日歷控件
更新時間:2010年03月24日 19:15:39 作者:
這種日歷控件實現(xiàn)起來不難,下面簡單分析下我的思路
這個日歷控件類似于園子用的日歷,如下圖:
...
settings:
{
firstDayOfWeek: 1,
baseClass: "calendar",
curDayClass: "curDay",
prevMonthCellClass: "prevMonth",
nextMonthCellClass: "nextMonth",
curMonthNormalCellClass: "",
prevNextMonthDaysVisible: true
},
...
weekDayNames: [],
...
其中有一半是用來控制單元格樣式的(不做過多描述),另外幾個(firstDayOfWeek,prevNextMonthDaysVisible,weekDayNames),意義如下:
firstDayOfWeek:日歷以星期幾做為第一天
prevNextMonthDaysVisible:是否顯示本月之外的日期
weekDayNames:星期的名稱(一個索引從1開始的數(shù)組,1處的值將作為周一的顯示名稱,以此類推)
接下來,進入生成html代碼階段:
1.生成日歷頭:
_RenderTitle: function(month, year) {
var ht = [];
//日期
ht.push("<tr>");
ht.push("<th colspan='7' style='width:100%;'><div style='float:left;width:10%;text-align:center;' id='", this.containerId, "_prevMonth' title='上一月'><</div><div style='float:left;text-align:center;width:80%'>", year, "年", month, "月</div><div style='float:right;width:10%; text-align:center;' id='", this.containerId, "_nextMonth' title='下一月'>></div></th>");
ht.push("</tr>");
//星期
ht.push("<tr>");
for (var i = 0; i < 7; i++) {
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
ht.push("<th>", this.weekDayNames[day], "</th>")
}
ht.push("</tr>");
return ht.join("");
},
日期部分為操作‘按鈕'的id使用日歷控件容器的id 作為前綴,以保證id唯一。
星期部分根據(jù)firstDayOfWeek的設(shè)置來獲取weekDayName。這里關(guān)鍵在于判斷每個單元格代表星期幾,思路很簡單:
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
這樣就可以取得當前單元格代表的星期了。
2.生成日歷的主要部分:
_RenderBody: function(month, year) {
var date = new Date(year, month - 1, 1);
var day = date.getDay();
var dayOfMonth = 1;
var daysOfPrevMonth = (7 - this.settings.firstDayOfWeek + day) % 7;
var totalDays = this._GetTotalDays(month, year);
var totalDaysOfPrevMonth = this._GetToalDaysOfPrevMonth(month, year);
var ht = [];
var curDate;
for (var i = 0; ; i++) {
curDate = null;
if (i % 7 == 0) {//新起一行
ht.push("<tr>");
}
ht.push("<td");
if (i >= daysOfPrevMonth && dayOfMonth <= totalDays) {//本月
curDate = new Date(year, month - 1, dayOfMonth);
if (Date.parse(new Date().toDateString()) - curDate == 0) {
ht.push(" class='", this.settings.curDayClass, "'");
}
else {
ht.push(" class='", this.settings.curMonthNormalCellClass, "'");
}
dayOfMonth++;
}
else if (i < daysOfPrevMonth) {//上月
if (this.settings.prevNextMonthDaysVisible) {
var prevMonth = month;
var prevYear = year;
if (month == 1) {
prevMonth = 12;
prevYear = prevYear - 1;
}
else {
prevMonth = prevMonth - 1;
}
curDate = new Date(prevYear, prevMonth - 1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
ht.push(" class='", this.settings.prevMonthCellClass, "'");
}
}
else {//下月
if (this.settings.prevNextMonthDaysVisible) {
var nextMonth = month;
var nextYear = year;
if (month == 12) {
nextMonth = 1;
nextYear = prevYear + 1;
}
else {
nextMonth = nextMonth + 1;
}
curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2);
ht.push(" class='", this.settings.nextMonthCellClass, "'");
}
}
ht.push(">");
ht.push(this._BuildCell(curDate));
ht.push("</td>");
if (i % 7 == 6) {//結(jié)束一行
ht.push("</tr>");
}
if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) {
break;
}
}
return ht.join("");
},
(1).獲取該月一號代表星期幾。這樣才能判斷1號應(yīng)該放到哪個單元格,也就是該月從哪個單元格開始(創(chuàng)建日期的時候month減了1,這是由于js Date對象本身的特性)。
(2).定義了一個標識變量 dayOfMonth ,用于控制本月日期顯示區(qū)域。
(3).計算要展示的上月的天數(shù)以及上月的總天數(shù)(不用計算下月要展示的天數(shù)和總天數(shù),因為下月要展示的日期是從1開始,最多不會超過6)。
(4).顯示本月的日期:
條件i >= daysOfPrevMonth && dayOfMonth <= totalDays決定了本月日期的顯示區(qū)域。
(5).顯示上月日期:
當i < daysOfPrevMonth 時即為上月日期的顯示區(qū)域。
(6). (4)、(5)之外當然就是下月日期的顯示區(qū)域了。
(7).何時結(jié)束:
從代碼看到for循環(huán)是沒有終止條件的,因此必須自己決定何時退出循環(huán):
if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) {
break;
}
i % 7 == 6表示一行結(jié)束, dayOfMonth - 1 >= totalDays表示本月日期已經(jīng)展示完畢。
(8).構(gòu)造curDate:
curDate代表每個單元格對應(yīng)的日期。
在顯示本月日期時, curDate = new Date(year, month - 1, dayOfMonth);
在顯示上月日期時, curDate = new Date(prevYear, prevMonth-1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
在顯示下月日期時, curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2),加2是由于i是從0開始,本身就少了1,dayOfMonth 在退出顯示本月日期時多加了一次.
最后,再來看看_BuildCell做了什么事情:
_BuildCell: function(curDate) {
var ht = [];
if (curDate) {
for (var j = 0; j < this.dateLinkMappings.length; j++) {
if (Date.parse(this.dateLinkMappings[j].Date) - curDate == 0) {
ht.push("<a href='", this.dateLinkMappings[j].Link, "'>", curDate.getDate(), "</a>");
break;
}
}
if (j == this.dateLinkMappings.length) {
ht.push(curDate.getDate());
}
}
else {
ht.push(" ");
}
return ht.join("");
},
事實上本日歷控件的意圖是用戶可以在初始化時傳入日期和該日期對應(yīng)的鏈接的映射的數(shù)組,也就是this.dateLinkMappings,當構(gòu)建單元格時若正在構(gòu)建的日期包含在this.dateLinkMappings里,則將當前單元格構(gòu)造成<a>形式,否則為普通的文本形式。
OK,實現(xiàn)邏輯大致如此,篇末看下演示效果:
前臺調(diào)用代碼如下:
var date = new Date();
var mapping = [];
mapping.push(new DateLinkMapping("3-22-2010", "javascript:alert(1)"));
mapping.push(new DateLinkMapping("4-1-2010", "javascript:alert(1)"))
Calendar.Init(null, mapping);
Calendar.RenderCalendar("myCalendar", date.getMonth() + 1, date.getFullYear());
打包下載地址
這種日歷控件實現(xiàn)起來不難,下面簡單分析下我的思路:
首先,是該控件的可配置項:
復(fù)制代碼 代碼如下:
...
settings:
{
firstDayOfWeek: 1,
baseClass: "calendar",
curDayClass: "curDay",
prevMonthCellClass: "prevMonth",
nextMonthCellClass: "nextMonth",
curMonthNormalCellClass: "",
prevNextMonthDaysVisible: true
},
...
weekDayNames: [],
...
其中有一半是用來控制單元格樣式的(不做過多描述),另外幾個(firstDayOfWeek,prevNextMonthDaysVisible,weekDayNames),意義如下:
firstDayOfWeek:日歷以星期幾做為第一天
prevNextMonthDaysVisible:是否顯示本月之外的日期
weekDayNames:星期的名稱(一個索引從1開始的數(shù)組,1處的值將作為周一的顯示名稱,以此類推)
接下來,進入生成html代碼階段:
1.生成日歷頭:
復(fù)制代碼 代碼如下:
_RenderTitle: function(month, year) {
var ht = [];
//日期
ht.push("<tr>");
ht.push("<th colspan='7' style='width:100%;'><div style='float:left;width:10%;text-align:center;' id='", this.containerId, "_prevMonth' title='上一月'><</div><div style='float:left;text-align:center;width:80%'>", year, "年", month, "月</div><div style='float:right;width:10%; text-align:center;' id='", this.containerId, "_nextMonth' title='下一月'>></div></th>");
ht.push("</tr>");
//星期
ht.push("<tr>");
for (var i = 0; i < 7; i++) {
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
ht.push("<th>", this.weekDayNames[day], "</th>")
}
ht.push("</tr>");
return ht.join("");
},
日期部分為操作‘按鈕'的id使用日歷控件容器的id 作為前綴,以保證id唯一。
星期部分根據(jù)firstDayOfWeek的設(shè)置來獲取weekDayName。這里關(guān)鍵在于判斷每個單元格代表星期幾,思路很簡單:
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
這樣就可以取得當前單元格代表的星期了。
2.生成日歷的主要部分:
復(fù)制代碼 代碼如下:
_RenderBody: function(month, year) {
var date = new Date(year, month - 1, 1);
var day = date.getDay();
var dayOfMonth = 1;
var daysOfPrevMonth = (7 - this.settings.firstDayOfWeek + day) % 7;
var totalDays = this._GetTotalDays(month, year);
var totalDaysOfPrevMonth = this._GetToalDaysOfPrevMonth(month, year);
var ht = [];
var curDate;
for (var i = 0; ; i++) {
curDate = null;
if (i % 7 == 0) {//新起一行
ht.push("<tr>");
}
ht.push("<td");
if (i >= daysOfPrevMonth && dayOfMonth <= totalDays) {//本月
curDate = new Date(year, month - 1, dayOfMonth);
if (Date.parse(new Date().toDateString()) - curDate == 0) {
ht.push(" class='", this.settings.curDayClass, "'");
}
else {
ht.push(" class='", this.settings.curMonthNormalCellClass, "'");
}
dayOfMonth++;
}
else if (i < daysOfPrevMonth) {//上月
if (this.settings.prevNextMonthDaysVisible) {
var prevMonth = month;
var prevYear = year;
if (month == 1) {
prevMonth = 12;
prevYear = prevYear - 1;
}
else {
prevMonth = prevMonth - 1;
}
curDate = new Date(prevYear, prevMonth - 1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
ht.push(" class='", this.settings.prevMonthCellClass, "'");
}
}
else {//下月
if (this.settings.prevNextMonthDaysVisible) {
var nextMonth = month;
var nextYear = year;
if (month == 12) {
nextMonth = 1;
nextYear = prevYear + 1;
}
else {
nextMonth = nextMonth + 1;
}
curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2);
ht.push(" class='", this.settings.nextMonthCellClass, "'");
}
}
ht.push(">");
ht.push(this._BuildCell(curDate));
ht.push("</td>");
if (i % 7 == 6) {//結(jié)束一行
ht.push("</tr>");
}
if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) {
break;
}
}
return ht.join("");
},
(1).獲取該月一號代表星期幾。這樣才能判斷1號應(yīng)該放到哪個單元格,也就是該月從哪個單元格開始(創(chuàng)建日期的時候month減了1,這是由于js Date對象本身的特性)。
(2).定義了一個標識變量 dayOfMonth ,用于控制本月日期顯示區(qū)域。
(3).計算要展示的上月的天數(shù)以及上月的總天數(shù)(不用計算下月要展示的天數(shù)和總天數(shù),因為下月要展示的日期是從1開始,最多不會超過6)。
(4).顯示本月的日期:
條件i >= daysOfPrevMonth && dayOfMonth <= totalDays決定了本月日期的顯示區(qū)域。
(5).顯示上月日期:
當i < daysOfPrevMonth 時即為上月日期的顯示區(qū)域。
(6). (4)、(5)之外當然就是下月日期的顯示區(qū)域了。
(7).何時結(jié)束:
從代碼看到for循環(huán)是沒有終止條件的,因此必須自己決定何時退出循環(huán):
復(fù)制代碼 代碼如下:
if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) {
break;
}
i % 7 == 6表示一行結(jié)束, dayOfMonth - 1 >= totalDays表示本月日期已經(jīng)展示完畢。
(8).構(gòu)造curDate:
curDate代表每個單元格對應(yīng)的日期。
在顯示本月日期時, curDate = new Date(year, month - 1, dayOfMonth);
在顯示上月日期時, curDate = new Date(prevYear, prevMonth-1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
在顯示下月日期時, curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2),加2是由于i是從0開始,本身就少了1,dayOfMonth 在退出顯示本月日期時多加了一次.
最后,再來看看_BuildCell做了什么事情:
復(fù)制代碼 代碼如下:
_BuildCell: function(curDate) {
var ht = [];
if (curDate) {
for (var j = 0; j < this.dateLinkMappings.length; j++) {
if (Date.parse(this.dateLinkMappings[j].Date) - curDate == 0) {
ht.push("<a href='", this.dateLinkMappings[j].Link, "'>", curDate.getDate(), "</a>");
break;
}
}
if (j == this.dateLinkMappings.length) {
ht.push(curDate.getDate());
}
}
else {
ht.push(" ");
}
return ht.join("");
},
事實上本日歷控件的意圖是用戶可以在初始化時傳入日期和該日期對應(yīng)的鏈接的映射的數(shù)組,也就是this.dateLinkMappings,當構(gòu)建單元格時若正在構(gòu)建的日期包含在this.dateLinkMappings里,則將當前單元格構(gòu)造成<a>形式,否則為普通的文本形式。
OK,實現(xiàn)邏輯大致如此,篇末看下演示效果:
前臺調(diào)用代碼如下:
復(fù)制代碼 代碼如下:
var date = new Date();
var mapping = [];
mapping.push(new DateLinkMapping("3-22-2010", "javascript:alert(1)"));
mapping.push(new DateLinkMapping("4-1-2010", "javascript:alert(1)"))
Calendar.Init(null, mapping);
Calendar.RenderCalendar("myCalendar", date.getMonth() + 1, date.getFullYear());
打包下載地址
相關(guān)文章
javascript 格式化時間日期函數(shù)代碼腳本之家修正版
javascript中,new Date()得到的是一個國際化時間格式的時間值 這在我們使用中文的時候,很不方便,也很難看所以就需要對javascript中的日期時間進行格式化.2009-12-12datePicker——日期選擇控件(with jquery)
用法很簡單,而且js文件也很小,之前也見過一些日期選擇控件,但個頭都比較大,影響速度2007-02-02JCalendar 日歷控件 v1.0 beta[兼容IE&Firefox] 有文檔和例子
JCalendar 日歷控件 v1.0 beta[兼容IE&Firefox] 有文檔和例子...2007-05-05關(guān)于js日期轉(zhuǎn)化為毫秒數(shù)“節(jié)省20%的效率和和節(jié)省9個字符“問題
最近在看松散耦合可定制百度的開源框架tangram.js目光突然就聚焦在一種獲得毫秒數(shù)的寫法2012-03-03javascript日期轉(zhuǎn)換 時間戳轉(zhuǎn)日期格式
javascript日期轉(zhuǎn)換 時間戳轉(zhuǎn)日期格式實現(xiàn)代碼,需要的朋友可以參考下。2011-11-11