JS學(xué)習(xí)之一個(gè)簡(jiǎn)易的日歷控件
這種日歷控件實(shí)現(xiàn)起來(lái)不難,下面簡(jiǎn)單分析下我的思路:
首先,是該控件的可配置項(xiàng):
...
settings:
{
firstDayOfWeek: 1,
baseClass: "calendar",
curDayClass: "curDay",
prevMonthCellClass: "prevMonth",
nextMonthCellClass: "nextMonth",
curMonthNormalCellClass: "",
prevNextMonthDaysVisible: true
},
...
weekDayNames: [],
...
其中有一半是用來(lái)控制單元格樣式的(不做過(guò)多描述),另外幾個(gè)(firstDayOfWeek,prevNextMonthDaysVisible,weekDayNames),意義如下:
firstDayOfWeek:日歷以星期幾做為第一天
prevNextMonthDaysVisible:是否顯示本月之外的日期
weekDayNames:星期的名稱(chēng)(一個(gè)索引從1開(kāi)始的數(shù)組,1處的值將作為周一的顯示名稱(chēng),以此類(lèi)推)
接下來(lái),進(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è)置來(lái)獲取weekDayName。這里關(guān)鍵在于判斷每個(gè)單元格代表星期幾,思路很簡(jiǎn)單:
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è)單元格開(kāi)始(創(chuàng)建日期的時(shí)候month減了1,這是由于js Date對(duì)象本身的特性)。
(2).定義了一個(gè)標(biāo)識(shí)變量 dayOfMonth ,用于控制本月日期顯示區(qū)域。
(3).計(jì)算要展示的上月的天數(shù)以及上月的總天數(shù)(不用計(jì)算下月要展示的天數(shù)和總天數(shù),因?yàn)橄略乱故镜娜掌谑菑?開(kāi)始,最多不會(huì)超過(guò)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)是沒(méi)有終止條件的,因此必須自己決定何時(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開(kāi)始,本身就少了1,dayOfMonth 在退出顯示本月日期時(shí)多加了一次.
最后,再來(lái)看看_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());
打包下載地址
相關(guān)文章
JS 倒計(jì)時(shí)實(shí)現(xiàn)代碼(時(shí)、分,秒)
JS 倒計(jì)時(shí)實(shí)現(xiàn)代碼,方便一些提示重要日期的來(lái)臨。2009-11-11javascript 格式化時(shí)間日期函數(shù)代碼腳本之家修正版
javascript中,new Date()得到的是一個(gè)國(guó)際化時(shí)間格式的時(shí)間值 這在我們使用中文的時(shí)候,很不方便,也很難看所以就需要對(duì)javascript中的日期時(shí)間進(jìn)行格式化.2009-12-12datePicker——日期選擇控件(with jquery)
用法很簡(jiǎn)單,而且js文件也很小,之前也見(jiàn)過(guò)一些日期選擇控件,但個(gè)頭都比較大,影響速度2007-02-02JCalendar 日歷控件 v1.0 beta[兼容IE&Firefox] 有文檔和例子
JCalendar 日歷控件 v1.0 beta[兼容IE&Firefox] 有文檔和例子...2007-05-05Javascript 日期對(duì)象Date擴(kuò)展方法
Date對(duì)象擴(kuò)展,包括常用中文日期格式解析、加減操作、日期差、周操作和季操作。2009-05-05關(guān)于js日期轉(zhuǎn)化為毫秒數(shù)“節(jié)省20%的效率和和節(jié)省9個(gè)字符“問(wèn)題
最近在看松散耦合可定制百度的開(kāi)源框架tangram.js目光突然就聚焦在一種獲得毫秒數(shù)的寫(xiě)法2012-03-03javascript日期轉(zhuǎn)換 時(shí)間戳轉(zhuǎn)日期格式
javascript日期轉(zhuǎn)換 時(shí)間戳轉(zhuǎn)日期格式實(shí)現(xiàn)代碼,需要的朋友可以參考下。2011-11-11