又重複造了個輪子,重複造輪子當然要有優點要不就沒有存在價值。使用簡單,方便。只要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'}) |
執行個體 (為控制項添加樣式) |