JS學(xué)習(xí)之一個(gè)簡易的日歷控件
更新時(shí)間:2010年03月24日 19:15:39 作者:
這種日歷控件實(shí)現(xiàn)起來不難,下面簡單分析下我的思路
這個(gè)日歷控件類似于園子用的日歷,如下圖:
...
settings:
{
firstDayOfWeek: 1,
baseClass: "calendar",
curDayClass: "curDay",
prevMonthCellClass: "prevMonth",
nextMonthCellClass: "nextMonth",
curMonthNormalCellClass: "",
prevNextMonthDaysVisible: true
},
...
weekDayNames: [],
...
其中有一半是用來控制單元格樣式的(不做過多描述),另外幾個(gè)(firstDayOfWeek,prevNextMonthDaysVisible,weekDayNames),意義如下:
firstDayOfWeek:日歷以星期幾做為第一天
prevNextMonthDaysVisible:是否顯示本月之外的日期
weekDayNames:星期的名稱(一個(gè)索引從1開始的數(shù)組,1處的值將作為周一的顯示名稱,以此類推)
接下來,進(jìn)入生成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)鍵在于判斷每個(gè)單元格代表星期幾,思路很簡單:
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
這樣就可以取得當(dāng)前單元格代表的星期了。
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).獲取該月一號(hào)代表星期幾。這樣才能判斷1號(hào)應(yīng)該放到哪個(gè)單元格,也就是該月從哪個(gè)單元格開始(創(chuàng)建日期的時(shí)候month減了1,這是由于js Date對(duì)象本身的特性)。
(2).定義了一個(gè)標(biāo)識(shí)變量 dayOfMonth ,用于控制本月日期顯示區(qū)域。
(3).計(jì)算要展示的上月的天數(shù)以及上月的總天數(shù)(不用計(jì)算下月要展示的天數(shù)和總天數(shù),因?yàn)橄略乱故镜娜掌谑菑?開始,最多不會(huì)超過6)。
(4).顯示本月的日期:
條件i >= daysOfPrevMonth && dayOfMonth <= totalDays決定了本月日期的顯示區(qū)域。
(5).顯示上月日期:
當(dāng)i < daysOfPrevMonth 時(shí)即為上月日期的顯示區(qū)域。
(6). (4)、(5)之外當(dāng)然就是下月日期的顯示區(qū)域了。
(7).何時(shí)結(jié)束:
從代碼看到for循環(huán)是沒有終止條件的,因此必須自己決定何時(shí)退出循環(huán):
if (i % 7 == 6 && dayOfMonth - 1 >= totalDays) {
break;
}
i % 7 == 6表示一行結(jié)束, dayOfMonth - 1 >= totalDays表示本月日期已經(jīng)展示完畢。
(8).構(gòu)造curDate:
curDate代表每個(gè)單元格對(duì)應(yīng)的日期。
在顯示本月日期時(shí), curDate = new Date(year, month - 1, dayOfMonth);
在顯示上月日期時(shí), curDate = new Date(prevYear, prevMonth-1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
在顯示下月日期時(shí), curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2),加2是由于i是從0開始,本身就少了1,dayOfMonth 在退出顯示本月日期時(shí)多加了一次.
最后,再來看看_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("");
},
事實(shí)上本日歷控件的意圖是用戶可以在初始化時(shí)傳入日期和該日期對(duì)應(yīng)的鏈接的映射的數(shù)組,也就是this.dateLinkMappings,當(dāng)構(gòu)建單元格時(shí)若正在構(gòu)建的日期包含在this.dateLinkMappings里,則將當(dāng)前單元格構(gòu)造成<a>形式,否則為普通的文本形式。
OK,實(shí)現(xiàn)邏輯大致如此,篇末看下演示效果:
前臺(tái)調(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());
打包下載地址
這種日歷控件實(shí)現(xiàn)起來不難,下面簡單分析下我的思路:
首先,是該控件的可配置項(xiàng):
復(fù)制代碼 代碼如下:
...
settings:
{
firstDayOfWeek: 1,
baseClass: "calendar",
curDayClass: "curDay",
prevMonthCellClass: "prevMonth",
nextMonthCellClass: "nextMonth",
curMonthNormalCellClass: "",
prevNextMonthDaysVisible: true
},
...
weekDayNames: [],
...
其中有一半是用來控制單元格樣式的(不做過多描述),另外幾個(gè)(firstDayOfWeek,prevNextMonthDaysVisible,weekDayNames),意義如下:
firstDayOfWeek:日歷以星期幾做為第一天
prevNextMonthDaysVisible:是否顯示本月之外的日期
weekDayNames:星期的名稱(一個(gè)索引從1開始的數(shù)組,1處的值將作為周一的顯示名稱,以此類推)
接下來,進(jìn)入生成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)鍵在于判斷每個(gè)單元格代表星期幾,思路很簡單:
var day = (i + this.settings.firstDayOfWeek) == 7 ? 7 : (i + this.settings.firstDayOfWeek) % 7;
這樣就可以取得當(dāng)前單元格代表的星期了。
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).獲取該月一號(hào)代表星期幾。這樣才能判斷1號(hào)應(yīng)該放到哪個(gè)單元格,也就是該月從哪個(gè)單元格開始(創(chuàng)建日期的時(shí)候month減了1,這是由于js Date對(duì)象本身的特性)。
(2).定義了一個(gè)標(biāo)識(shí)變量 dayOfMonth ,用于控制本月日期顯示區(qū)域。
(3).計(jì)算要展示的上月的天數(shù)以及上月的總天數(shù)(不用計(jì)算下月要展示的天數(shù)和總天數(shù),因?yàn)橄略乱故镜娜掌谑菑?開始,最多不會(huì)超過6)。
(4).顯示本月的日期:
條件i >= daysOfPrevMonth && dayOfMonth <= totalDays決定了本月日期的顯示區(qū)域。
(5).顯示上月日期:
當(dāng)i < daysOfPrevMonth 時(shí)即為上月日期的顯示區(qū)域。
(6). (4)、(5)之外當(dāng)然就是下月日期的顯示區(qū)域了。
(7).何時(shí)結(jié)束:
從代碼看到for循環(huán)是沒有終止條件的,因此必須自己決定何時(shí)退出循環(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代表每個(gè)單元格對(duì)應(yīng)的日期。
在顯示本月日期時(shí), curDate = new Date(year, month - 1, dayOfMonth);
在顯示上月日期時(shí), curDate = new Date(prevYear, prevMonth-1, totalDaysOfPrevMonth - (daysOfPrevMonth - i - 1));
在顯示下月日期時(shí), curDate = new Date(nextYear, nextMonth-1, i - dayOfMonth - daysOfPrevMonth + 2),加2是由于i是從0開始,本身就少了1,dayOfMonth 在退出顯示本月日期時(shí)多加了一次.
最后,再來看看_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("");
},
事實(shí)上本日歷控件的意圖是用戶可以在初始化時(shí)傳入日期和該日期對(duì)應(yīng)的鏈接的映射的數(shù)組,也就是this.dateLinkMappings,當(dāng)構(gòu)建單元格時(shí)若正在構(gòu)建的日期包含在this.dateLinkMappings里,則將當(dāng)前單元格構(gòu)造成<a>形式,否則為普通的文本形式。
OK,實(shí)現(xiàn)邏輯大致如此,篇末看下演示效果:
前臺(tái)調(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)文章
datePicker——日期選擇控件(with jquery)
用法很簡單,而且js文件也很小,之前也見過一些日期選擇控件,但個(gè)頭都比較大,影響速度2007-02-02
IE與Firefox下javascript getyear年份的兼容性寫法
IE與Firefox下javascript getyear年份導(dǎo)致日期不統(tǒng)一的解決方法2007-12-12
javascript 時(shí)間顯示代碼集合(Date對(duì)象)
javascript提供了Date對(duì)象來進(jìn)行時(shí)間和日期的計(jì)算,所以我們后面的很多代碼都是通過Date對(duì)象實(shí)現(xiàn)的,大家多看一些實(shí)例就可以自己拓展了2012-09-09
javascript時(shí)區(qū)函數(shù)介紹
在js中的時(shí)區(qū)我們以般講的是關(guān)于格林威治時(shí)間和本地時(shí)間之間的時(shí)差,以分鐘為單位,這和php,asp沒什么區(qū)別下面我們結(jié)合date()函數(shù)來介紹一下js時(shí)區(qū)的相關(guān)問題2012-09-09
自己整理的一個(gè)javascript日期處理函數(shù)
日期函數(shù),沒必要多說了吧?就是一般的日期比較,日期相加,獲取當(dāng)前time2010-10-10

