具體要求就是:
1、日期表格橫向佔滿頁面。
2、每個月的日期列表橫向顯示在一排,而不是像網上的很多日期控制項顯示一個方塊。
3、要求只有年月日可選,選擇年或月後自動更新對應日期(這個每個日期控制項都有的)。
4、預設顯示當前年月,高亮當前日期,並顯示當前的周次(本年第幾周)和星期幾。
5、選擇某個日期後高亮顯示當前日期,並自動更新周次和星期顯示。
6、提供介面,可以設定特定日期的顯示樣式。
6、其他就是一些介面展示的問題了。
想著就是一個日期控制項,做著也比較簡單,不過比較特別是橫向的,第一次聽說這種需求的!
偶還是第一次寫日曆類的東西,不過這次的麻煩還是在於周次的計算上和最後提供的設定特定日期的介面實現上,但經過一番分析也很好的解決了。
主要幾個總結:
1、使用了閉包,隱藏內建函式及變數,防止變數汙染。最後只提供一個對外介面:setDateStyle
2、計算每年二月的天數不是通過判斷閏年的辦法,而是通過判斷是否2月29日存在,如果不存在則為28天。
3、計算周次要先計算當前日期是本年的第幾天,同時要考慮本年1月1日是星期幾,然後計算即可得出。
4、setDateStyle支援單個日期樣式的傳入,也支援多個日期樣式的設定。對於樣式的更新主要採用數組合并字元竄,並採用字串的indexOf方法匹配並執行樣式的設定。
5、CSS/JS/HTML相分離,便於維護。函數模組化便於重用。
複製代碼 代碼如下:
var logDateControl=(function(){
var curSelEl; //當前選中的日期
var styleData=[],dataStyle={};
//擷取指定id的元素
var $=function(id){return document.getElementById(id)}
//計算指定日期是第幾周(預設為當前日期),該計算方法比較嚴密準確
var calWeek=function(dt){
var calDay=dt||new Date(); //當前要計算的時間
var firstDay=new Date(calDay.getFullYear(),0,1); //本年第一天
//計算當前是本年的第幾天,00:00為當天開始
var daysAll=Math.floor((calDay-firstDay)/1000/60/60/24)+1;
//本年第一天星期幾
var firstDayWeekday=firstDay.getDay();
//該結果加到第一周的周一,便於後面計算
var diffDay=firstDayWeekday==0?6:firstDayWeekday-1;
daysAll=daysAll+diffDay;
return Math.ceil(daysAll/7); //返回計算結果
}
//計算一個月多少天,年份4位元字,月份1-2位元字(應該是js日期格式如1月傳入0),資料非法返回-1
var getDaysLen=function(year,month){
if(!(/^\d{4}$/.test(year)&&/^\d{1,2}$/.test(month))){return -1}
var monthDays=[31,28,31,30,31,30,31,31,30,31,30,31]
//存在2月29日
if(month==1&&new Date(year,1,29).getMonth()==1){monthDays[1]=29}
return monthDays[month]
}
//顯示日期列表,傳入年、月(按日常月份傳入。如二月傳入2)、及顯示位置
var displayDayList=function(year,month,pos){
var daysList=[];
var cells1=$(pos).rows[0].cells;
var cells2=$(pos).rows[1].cells;
var daysArr=['日','一','二','三','四','五','六'];
//下面的month-1轉換為js月份表示
for(var i=1,l=getDaysLen(year,--month)+1;i<l;i++){
var wd=new Date(year,month,i).getDay();
cells1[i-1].className="";
if(wd==0||wd==6){cells1[i-1].className="weekEnd";} //為周末添加特殊樣式
//_oldCls儲存當前日期的預設樣式
cells1[i-1].innerText=daysArr[wd];
cells2[i-1].className="unSelectDay";
cells2[i-1].setAttribute("_oldCls","unSelectDay");
cells2[i-1].innerText=i>9?i:"0"+i;
//匹配使用者自訂樣式
var dtStr=year+"|"+(month+1)+"|"+i;
if((","+styleData.join(',')+",").indexOf(","+dtStr+",")>-1){
cells2[i-1].className="unSelectDay "+dataStyle[dtStr];
cells2[i-1].setAttribute("_oldCls","unSelectDay "+dataStyle[dtStr]);
}
}
//如果是當前月則選中當日
if(new Date().getMonth()==month){
curSelEl=cells2[new Date().getDate()-1];
curSelEl.className="selectDay";
}
for(var j=i-1;j<31;j++){
cells1[j].className=cells2[j].className="";
cells1[j].innerHTML=cells2[j].innerHTML=" ";
}
$(pos).onclick=function(){changeInfo()}
}
//根據選擇的值進行處理周次和周幾的調整,可以直接傳入儲存日期內容的dom元素,或者函數根據點擊位置判斷
var changeInfo=function(e){
e=e||event;
var el=e.target||e.srcElement||e; //最後一個e:可能是傳入的對象
var day=el.innerText;
if(!/^\d{1,2}$/.test(day)) return; //如果不是日期什麼都不做
//恢複之前選中日期的樣式
if(curSelEl){curSelEl.className=curSelEl.getAttribute("_oldCls")}
curSelEl=el; //儲存當前處理的元素
//更新選中日期的樣式
el.className="selectDay";
var dt=new Date($("year").value,$("month").value-1,day);
//更新資訊
$("day").value=day; //日期
$("weekday").value=['日','一','二','三','四','五','六'][dt.getDay()]; //星期幾
$("week").value=calWeek(dt); //第幾周
}
//初始化
window.attachEvent("onload",function(){
var curDate=new Date(),curYear=curDate.getFullYear();
//顯示上下十年
for(var i=-10;i<10;i++){$("year").add(new Option(curYear+i,curYear+i))}
$("year").selectedIndex=10; //預設選中當前年份
$("month").selectedIndex=curDate.getMonth(); //當前月份
$("day").value=curDate.getDate(); //當前日期
$("weekday").value=['日','一','二','三','四','五','六'][curDate.getDay()]; //當前星期幾
$("week").value=calWeek(); //當前第幾周
//改變日期或年份更新日期列表
$("year").onchange=$("month").onchange=function(){displayDayList($("year").value,$("month").value,"daysList")};
//顯示當月日期列表,並高亮當天的日期
displayDayList(curDate.getFullYear(),curDate.getMonth()+1,"daysList");
});
//對外設定樣式的介面。
//格式:([2007,10,12],"color:#f00") ([[2007,10,20],[2007,11,25]],"color:#00f")
//如果月份小於10不要帶0
var setDateStyle=function(dateArr,style){
if(typeof dateArr!="object")return;
if(dateArr instanceof Array){
if(dateArr[0] instanceof Array){
for(var i=0;i<dateArr.length;i++) setDateStyle(dateArr[i],style);
}
var dataStr=dateArr.join('|');
styleData.push(dataStr);
dataStyle[dataStr]=style;
return;
}
}
//對外介面
return {setDateStyle:setDateStyle}
})();
//測試樣式設定
logDateControl.setDateStyle([[2007,12,15],[2007,11,12]],"test");
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title> new document </title> <meta name="generator" content="editplus" /> <meta name="author" content="" /> <meta name="keywords" content="" /> <meta name="description" content="" /> <style type="text/css"> *{font-size:14px} /*日期最外層*/ #logCalendar{width:950px;border-top:1px solid #ccc;border-left:1px solid #ccc} /*日期內部所有儲存格*/ #logCalendar td{ border-right:1px solid #ccc;border-bottom:1px solid #ccc; padding-left:5px;text-align:center; height:22px;line-height:22px; } #daysList{border-top:1px solid #ccc;border-left:1px solid #ccc} /*日期列表所有儲存格*/ #daysList td{text-align:center;height:22px} /*周次及星期幾的輸入框*/ .bd{border:0;text-align:center;color:#00f} /*日期預設樣式*/ .unSelectDay{ color:#00f;font-weight:normal; padding:3px;cursor:pointer; text-decoration:underline } /*當前點擊的日期樣式*/ .selectDay{color:#fff;font-weight:bold;background:#FEB0B0;padding:1px;text-decoration:none;cursor:normal} /*周末樣式*/ .weekEnd{color:#f00} .test{color:#f00;text-decoration:none} </style> <script type="text/javascript"> //2007-12-21 工作日誌日期組件 yanwei //使用閉包隱藏所有變數和函數,防止與外界衝突 var logDateControl=(function(){ var curSelEl; //當前選中的日期 var styleData=[],dataStyle={}; //擷取指定id的元素 var $=function(id){return document.getElementById(id)} //計算指定日期是第幾周(預設為當前日期),該計算方法比較嚴密準確 var calWeek=function(dt){ var calDay=dt||new Date(); //當前要計算的時間 var firstDay=new Date(calDay.getFullYear(),0,1); //本年第一天 //計算當前是本年的第幾天,00:00為當天開始 var daysAll=Math.floor((calDay-firstDay)/1000/60/60/24)+1; //本年第一天星期幾 var firstDayWeekday=firstDay.getDay(); //該結果加到第一周的周一,便於後面計算 var diffDay=firstDayWeekday==0?6:firstDayWeekday-1; daysAll=daysAll+diffDay; return Math.ceil(daysAll/7); //返回計算結果 } //計算一個月多少天,年份4位元字,月份1-2位元字(應該是js日期格式如1月傳入0),資料非法返回-1 var getDaysLen=function(year,month){ if(!(/^\d{4}$/.test(year)&&/^\d{1,2}$/.test(month))){return -1} var monthDays=[31,28,31,30,31,30,31,31,30,31,30,31] //存在2月29日 if(month==1&&new Date(year,1,29).getMonth()==1){monthDays[1]=29} return monthDays[month] } //顯示日期列表,傳入年、月(按日常月份傳入。如二月傳入2)、及顯示位置 var displayDayList=function(year,month,pos){ var daysList=[]; var cells1=$(pos).rows[0].cells; var cells2=$(pos).rows[1].cells; var daysArr=['日','一','二','三','四','五','六']; //下面的month-1轉換為js月份表示 for(var i=1,l=getDaysLen(year,--month)+1;i<l;i++){ var wd=new Date(year,month,i).getDay(); cells1[i-1].className=""; if(wd==0||wd==6){cells1[i-1].className="weekEnd";} //為周末添加特殊樣式 //_oldCls儲存當前日期的預設樣式 cells1[i-1].innerText=daysArr[wd]; cells2[i-1].className="unSelectDay"; cells2[i-1].setAttribute("_oldCls","unSelectDay"); cells2[i-1].innerText=i>9?i:"0"+i; //匹配使用者自訂樣式 var dtStr=year+"|"+(month+1)+"|"+i; if((","+styleData.join(',')+",").indexOf(","+dtStr+",")>-1){ cells2[i-1].className="unSelectDay "+dataStyle[dtStr]; cells2[i-1].setAttribute("_oldCls","unSelectDay "+dataStyle[dtStr]); } } //如果是當前月則選中當日 if(new Date().getMonth()==month){ curSelEl=cells2[new Date().getDate()-1]; curSelEl.className="selectDay"; } for(var j=i-1;j<31;j++){ cells1[j].className=cells2[j].className=""; cells1[j].innerHTML=cells2[j].innerHTML=" "; } $(pos).onclick=function(){changeInfo()} } //根據選擇的值進行處理周次和周幾的調整,可以直接傳入儲存日期內容的dom元素,或者函數根據點擊位置判斷 var changeInfo=function(e){ e=e||event; var el=e.target||e.srcElement||e; //最後一個e:可能是傳入的對象 var day=el.innerText; if(!/^\d{1,2}$/.test(day)) return; //如果不是日期什麼都不做 //恢複之前選中日期的樣式 if(curSelEl){curSelEl.className=curSelEl.getAttribute("_oldCls")} curSelEl=el; //儲存當前處理的元素 //更新選中日期的樣式 el.className="selectDay"; var dt=new Date($("year").value,$("month").value-1,day); //更新資訊 $("day").value=day; //日期 $("weekday").value=['日','一','二','三','四','五','六'][dt.getDay()]; //星期幾 $("week").value=calWeek(dt); //第幾周 } //初始化 window.attachEvent("onload",function(){ var curDate=new Date(),curYear=curDate.getFullYear(); //顯示上下十年 for(var i=-10;i<10;i++){$("year").add(new Option(curYear+i,curYear+i))} $("year").selectedIndex=10; //預設選中當前年份 $("month").selectedIndex=curDate.getMonth(); //當前月份 $("day").value=curDate.getDate(); //當前日期 $("weekday").value=['日','一','二','三','四','五','六'][curDate.getDay()]; //當前星期幾 $("week").value=calWeek(); //當前第幾周 //改變日期或年份更新日期列表 $("year").onchange=$("month").onchange=function(){displayDayList($("year").value,$("month").value,"daysList")}; //顯示當月日期列表,並高亮當天的日期 displayDayList(curDate.getFullYear(),curDate.getMonth()+1,"daysList"); }); //對外設定樣式的介面。 //格式:([2007,10,12],"color:#f00") ([[2007,10,20],[2007,11,25]],"color:#00f") //如果月份小於10不要帶0 var setDateStyle=function(dateArr,style){ if(typeof dateArr!="object")return; if(dateArr instanceof Array){ if(dateArr[0] instanceof Array){ for(var i=0;i<dateArr.length;i++) setDateStyle(dateArr[i],style); } var dataStr=dateArr.join('|'); styleData.push(dataStr); dataStyle[dataStr]=style; return; } } //對外介面 return {setDateStyle:setDateStyle} })(); //測試樣式設定 logDateControl.setDateStyle([[2007,12,15],[2007,11,12]],"test"); </script> </head> <body> <table cellpadding="3" cellspacing="0" id="logCalendar"> <tr> <td>第<input type="text" name="week" class="bd" readonly size="2">周</td> <td>星期<input type="text" name="weekday" class="bd" readonly size="2"></td> <td rowspan="2" > <table width="100%" cellpadding="3" height="100%" cellspacing="0" id="daysList"> <tr> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td><td></td> </tr> <tr> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td> <td></td><td></td><td></td><td></td><td></td><td></td> </tr> </table> </td> </tr> <tr> <td><select name="year" id="year"></select>年 <select name="month" id="month"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> </select>月</td> <td>日期<input type="text" name="day" size="2" class="bd" id="day"></td> </tr> </table> </body> </html>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]