又重復造了個輪子,重復造輪子當然要有優點要不就沒有存在價值。使用簡單,方便。只要5行代碼就可生成年歷。
input date已經是一個原生控件opera和chrome已經支持,日歷控件邏輯比較復雜,要做到盡善盡美也是不容易的,也是比較鍛煉編碼的,所以學習意義大於實際意義。而且這個控件也是多年心願,最近有時間寫寫停停,終於堅持下來就拿來和大家分享了。
特點
1.此日歷插件特點在於簡單易用,要保證功能實現最低要求一個參數。
2.個性化配置有強大的自定義事件和多個個性化參數可選。
3.采用原型繼承,擴展派生非常方便。
4.跨瀏覽器,保證可用性。
5.采用表格做載體,無樣式也可以正常使用功能。
6.緩存,已生成月份數據。使數據持久化,減少計算。
7.無樣式支持,功能依然健在。

應用展示
a.

b.

c.

技術總結
1.主要難點不是日期算法,而是select控件和表格所帶來的問題。select和表格都有一套自己的dom api,來操作和訪問。尤其是生成日歷table的算法非了一些時間,而且ie瀏覽器上。innerHTML屬性,table tbody tfoot tr都是只讀的,所以對技術選型有一些干擾。中間使用了insertRow這樣的方法未果,采用分辨瀏覽器采用不同方案也行不通后,過段采用整個table都用拼字符串的方式。雖然效率不一定比生成dom節點存入變量修改高,但是結果卻是最好的。
2.select主要問題在於序號和長度差,要訪問selectedIndex,設置select的值都要小心這個變化。
3.Date對象的序號問題,年 日都是從1開始,月份是從0開始,這些差別和人類習慣的處理帶來一定成本。
可見初期,技術儲備和技術選型的重要性。
其實日期核心算法只有5行代碼而已,想要生成一個可用的日期控件20行內代碼足夠,由於和日期控件相關的控件出來帶來了大量代碼。
核心代碼
1。計算某個月有多少天,2012.6月到底有多少天呢?我們要是知道6月最后一天是多少號,不就知道6月有多少天了嗎。
new Date('2012,6,0').getDate();最簡單最短 //chrome不支持用字符串new Date('2012,6,0')格式創建日期, 但支持new Date('2012','6','0');這點要注意 而safari沒有問題非常詭異
通用的
(new Date(+(new Date(2012, 7, 1)) - 86400000)).getDate();
下個月的一號減去一天,就是當月最后一天
2.知道了當月有多少天還不行,要知道當月1號是要放在什么位置,如果知道1號是星期幾不就可以知道1號在什么位置了嗎。
new Date(2012, 7,1).getDay();
3.生成一個月的日歷,代碼很簡單只有5行
for (var i = 0; i < row; i++) {
html.push('</tr>');
for (var j = 0; j < 7; j++) {
html.push((cell-- <= offset && days > 0) ? ('<td ' + (that.Date > new Date(y, m, days + 1) ? 'class="oldDay"' : '') + (y === that.Year && m === that.Month && days === that.Day ? 'class="currentDay"' : '') + ' title="'+y+that.style+(m+1)+that.style+days+'">' + (days--) + '</td>') : '<td></td>');
}
html.push('<tr>');
}
大家可能要懷疑為什么先寫的是 </tr>結束標簽,開始生成日歷的時候采用的是倒序循環,用li標簽,后面發現無樣式時不能使用,所以改用table但這一方式保留下來,日期也是按照從后往前生成的。然后調用數組的reverse反向join就正序了。
4.一個實例的6月份數據和另外一個實例的6月份數據有不同點么,或者重復使用6月份數據需要每次都計算么,答案顯然不是。相同月份的數據多次使用要是只計算一次的話就可以大大提高效率,減少計算次數。
那么這就牽扯到數據持久化的問題,怎樣把數據持久化呢或者暫時持久化?答案是把數據保存在類的屬性上隨用隨拿。
var key = '_date_:' + Y + ':' + M; indicotar.cache[key] || (indicotar.cache[key] = that.getDateString(Y, M));
按照年月生成一個key,如果沒有數據就調用方法生成數據存入對應key的value。以后只用只用取出,合並字符串即可。

API
constructor:Cal(可以自行修改無依賴);實例化:new Cal(document.body);
返回值:實例對象;
| Node | *htmlNode | nodeType為1的節點,控件會被append此節點內 |
| Object | O | 配置控件可選參數 |
| Number | O.Y | 設置的年份,默認當年,范圍(1970-當年+10) |
| Number | O.M | 設置的月份,默認當月,范圍(1-12) |
| String | O.hasTitle | 是否有日期控制欄,默認有'true' |
| String | O.hasFoot | 是否有腳注用來顯示年月,默認無'false' |
| String | O.style | 日期分隔符,默認'-' |
| Number | O.startYear | 開始年,默認2006 |
| Number | O.endtYear | 結束年,默認當年加10 |
| Function | O.ongetdate | 用戶點擊日期單元格時觸發,this指向實例,第一個參數為日期對應數組 |
| Function | O.onrender | 控件插入值dom樹時觸發,this指向實例,第一個參數為控件對應的dom節點 |
| Function | O.ongetdatestring | 獲得月份所對應的日期字符串時觸發,this指向實例,第一個參數為字符串 |
| Function | O.oncalframe | 組成完畢控件node框架時觸發,this指向實例,第一個參數為對應的dom節點 |
| Function | fn | 類的回調函數,生成控件后觸發 |
| 方法名 | 參數 | 返回值 |
| createDay | Y:number/string(2012),M:number/string(0-11) | 實例(1儲存日期字符串至Cal的cache中,是數據持久化;2調用render) |
| render | node:(this.elems),key:string('_date_:2012:0'),Y:number(2012),M:number(0-11) | 實例(渲染控件至dom樹) |
| getDateString | Y:number(2012),M:number(0-11) | htmlString |
| toString | string '2012-12-12' (獲取選中日期對應的字符串) | |
| valueOf | Array [2012,12,12] (獲取選中日期對應的數組) | |
| hide | 實例 (隱藏控件) | |
| show | 實例 (顯示控件) | |
| setCss | Object({'font-size':'12px','width':'300px'}) | 實例 (為控件添加樣式) |
