打造基於jQuery的日期選擇控件

終於把jQuery拼寫正確了哈,哈哈javascript也是區分大小寫的,因此確實不能寫錯,今天我來和你們分享的是日期選擇控件的實現,功能也許不夠強大,可是可以知足需求。javascript

我以前也寫過(正確的說是改過一個日期選擇控件,點擊這裏查看),看下截圖哈,也很酷的,windows風格哦。
css

可是也有些問題,第一畫日曆有點慢,第二兼容性不太好IE Only,第三它不是基於jQuery的哈哈。html

那仍是老規矩,作以前先看下效果java

image  image

這下是更酷的Ext風格了。
從上圖咱們能夠看出這個控件其實有兩個視圖一個日期月視圖,還有一個是年月選擇視圖。
1:仍是先從HTML入手windows

日期控件肯定HTML其實仍是比較簡單,由於明擺着是列表的數據格式,固然主要是採用table了。
兩個視圖分別用兩個Div包裹,控制div的顯示隱藏便可以切換視圖了。完整的HTMl結構你們能夠用IEDeveloper看一下Demo的結構,我本身截了一個圖
image 數組

2:根據HTML和效果圖編寫CSSapp

其實由於是Ext風格的,因此直接copy的ext的css和圖片。。ssh

CSS也就不分析了,直接上代碼。ide

由於博客園的語法高亮不支持CSS,因此就不貼出來了,給個下載地址吧:函數

 http://xuanye.cloudapp.net/Theme/Default/dp.css

全部用到的圖片:

btn-arrow btn-arrow-light cal

3:搞定了CSS以後呢,就開始編寫咱們javascript了。

上來就是一個完整代碼

那接着就是分析一下實現的主要過程和一些注意的要點:

首先仍是套版化編寫jQuery控件的套子:

1
2
3
4
5
;( function ($) {     
     //也可使用$.fn.extend(datepicker:function(o){})     
     $.fn.datepicker= function (o) { 
                 }
})(jQuery);

這樣作的好處上篇已經講過了 ,就不重述了
接着就是定義默認的參數,已在代碼中添加了註釋說明這些參數的意義,有幾個參數是爲了多語言而設置的,如weekName,monthName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var def = {
             weekStart: 0, //一週開始的是星期幾0表明星期天
             weekName: [ "日" , "一" , "二" , "三" , "四" , "五" , "六" ], //星期的格式
             monthName: [ "一" , "二" , "三" , "四" , "五" , "六" , "七" , "八" , "九" , "十" , "十一" , "十二" ], //月份的格式
             monthp: "月" , //月的後綴
             Year: new Date().getFullYear(), //定義年的變量的初始值
             Month: new Date().getMonth() + 1, //定義月的變量的初始值
             Day: new Date().getDate(), //定義日的變量的初始值
             today: new Date(), //today
             btnOk: " 肯定 " , //肯定按鈕的文字
             btnCancel: " 取消 " , //取消按鈕的文字
             btnToday: "今天" , //今天按鈕的文字
             inputDate: null , //無用,只是在代碼中會用它存放數據
             onReturn: false , //當選擇日期後回調的函數
             version: "1.0" , //版本
             applyrule: false , //日期選擇規則,可設置可選擇的日期範圍function(){};return rule={startdate,endate};
             showtarget: null , //顯示載體,日曆展開式所依賴的對象,默認是對象自己
             picker: "" //附加點擊事件的對象
         };
     $.extend(def, o); //用傳遞過來的參數來填充默認

第二部天然是初始化月視圖和年月選擇視圖的HTML了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//給日期選擇控件一個特殊的ID,獲取這個ID的對象,判斷若是對象存在,則直接使用
// 日期的HTML採用單例,即一個頁面上只生成一份HTML
   var cp = $( "#BBIT_DP_CONTAINER" );
 
         if (cp.length == 0) {
             var cpHA = []; //老規矩仍是用數組拼接html,最後用innerHTML的方式附加到容器,提高性能
             cpHA.push( "<div id='BBIT_DP_CONTAINER' class='bbit-dp' style='width:175px;z-index:999;'>" );
             if ($.browser.msie6) { //若是是IE6彈出層遮蓋select
                 cpHA.push( '<iframe style="position:absolute;z-index:-1;width:100%;height:100%;top:0;left:0;scrolling:no;" frameborder="0" src="about:blank"></iframe>' );
             }
             cpHA.push( "<table class='dp-maintable' cellspacing='0' cellpadding='0' style='width:175px;'><tbody><tr><td>" );
             //頭喲
             cpHA.push( "<table class='bbit-dp-top' cellspacing='0'><tr><td class='bbit-dp-top-left'> <a id='BBIT_DP_LEFTBTN' href='javascript:void(0);' title='向前一個月'>&nbsp;</a></td><td class='bbit-dp-top-center' align='center'><em><button id='BBIT_DP_YMBTN'>九月 2009</button></em></td><td class='bbit-dp-top-right'><a id='BBIT_DP_RIGHTBTN' href='javascript:void(0);' title='向後一個月'>&nbsp;</a></td></tr></table>" );
             cpHA.push( "</td></tr>" );
             cpHA.push( "<tr><td>" );
             //周
             cpHA.push( "<table id='BBIT_DP_INNER' class='bbit-dp-inner' cellspacing='0'><thead><tr>" );
             //生成周
             for ( var i = def.weekStart, j = 0; j < 7; j++) {
                 cpHA.push( "<th><span>" , def.weekName[i], "</span></th>" );
                 if (i == 6) { i = 0; } else { i++; }
             }
         
             ..... //省略若干代碼
             cpHA.push( "</tbody></table>" );
             cpHA.push( "</div>" );
             cpHA.push( "</div>" );
 
             var s = cpHA.join( "" );
             $(document.body).append(s); //添加到body中
             cp = $( "#BBIT_DP_CONTAINER" ); //再獲取一遍
 
             initevents(); //初始化事件
         }

這裏有一個關鍵點,就是日期的html輸出和事件初始化只作一次,由於基本上一頁上同時不會打開兩個。還有就是生成html中有一些特殊的自定義屬性哦,仔細看下就會發現的,這些屬性在後面的時間處理中都有很大的做用。那麼來看一下事件吧

1
2
3
4
5
6
7
8
9
10
11
$( "#BBIT-DP-TODAY" ).click(returntoday); //今天按鈕的事件
          cp.click(returnfalse); //阻止冒泡
          $( "#BBIT_DP_INNER tbody" ).click(tbhandler); //給月視圖中間body添加click事件而不是給每一個td添加
          $( "#BBIT_DP_LEFTBTN" ).click(prevm); //上個月
          $( "#BBIT_DP_RIGHTBTN" ).click(nextm); //下個月
          $( "#BBIT_DP_YMBTN" ).click(showym); //切換到年月視圖
          $( "#BBIT-DP-MP" ).click(mpclick); //年月視圖的點擊事件,一樣用於分發
          $( "#BBIT-DP-MP-PREV" ).click(mpprevy); //上一年
          $( "#BBIT-DP-MP-NEXT" ).click(mpnexty); //下一年
          $( "#BBIT-DP-MP-OKBTN" ).click(mpok); //ok按鈕的事件
          $( "#BBIT-DP-MP-CANCELBTN" ).click(mpcancel); //cancel按鈕的事件

給每個須要點擊的元素加上事件哦,這裏有兩個地方比較特殊,一個是月視圖的點擊事件,傳統的作法就是給每一個td都加事件,可是這個時候個人td尚未呢,可是若是在每次生成td的時候來附加事件,那麼就由影響性能,因此直接給容器加了點擊事件,經過對事件源的判斷來分發事件,另一個年月選擇視圖,也是和上面同樣的邏輯,那麼咱們就拿月視圖的點擊事件來分析一下,其實每個td生成的時候都會註冊一個xdate自定義屬性 image ,來看一下tbhandler函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function tbhandler(e) {
             var et = e.target || e.srcElement; //找到事件源
             var td = getTd(et); //事件源遞歸往上找td
             if (td == null ) {
                 return false ;
             }
             var $td = $(td);
             if (!$(td).hasClass( "bbit-dp-disabled" )) { //若是不是禁用狀態
                 var s = $td.attr( "xdate" ); //獲取td的自定義屬性日期數據
                 var arrs = s.split( "-" );
                 cp.data( "indata" , new Date(arrs[0], parseInt(arrs[1], 10) - 1, arrs[2]));
                 returndate(); //返回日期
             }
             return false ;
         }

全部的日期選擇事件初始化好了(一次性的),接着就要給每個的picker添加點擊事件了

1
2
3
4
5
6
7
8
9
10
11
12
return $( this ).each( function () {
             var obj = $( this ).addClass( "bbit-dp-input" ); //給input添加樣式
             var picker = $(def.picker); //獲取picker對象
             //若是showtarget不爲null這將picker註冊到input的後面
             //不然用戶本身處理picker的位置,即picker在頁面上自己就已經存在
             //你們能夠看看示例中1,3調用的區別
             def.showtarget == null && obj.after(picker);
             
             picker.click( function (e) {
 
... //省略代碼
});

picker的點擊事件比較長,單獨拿出來說一下我想比較好,第一個要點是顯示隱藏事件的處理,第二個是窗口邊緣問題的處理,還有一個就是日期範圍規則的處理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
function (e) {
//獲取當前是否顯示
                 var isshow = $( this ).attr( "isshow" );
                 
                 var me = $( this );
                 //若是顯示着,則隱藏,用於處理點擊一下picker顯示,再點擊picker隱藏的邏輯
                 if (cp.css( "visibility" ) == "visible" ) {
                     cp.css( " visibility" , "hidden" );
                 }
                 //一樣是若是顯示着
                 if (isshow == "1" ) {
                     me.attr( "isshow" , "0" );
                     //remover臨時數據,由於是單例因此要表示當前是哪一個input
                     cp.removeData( "ctarget" ).removeData( "cpk" ).removeData( "indata" ).removeData( "onReturn" );
                     return false ; //阻止冒泡
                 }
                 //若是隱藏着,獲取input的值
                 var v = obj.val();
                 if (v != "" ) {
                     v = v.match(dateReg); //驗證一下格式是否正確
                 }
                 if (v == null || v == "" ) { //格式不正確或爲空則用當前日期
                     def.Year = new Date().getFullYear();
                     def.Month = new Date().getMonth() + 1;
                     def.Day = new Date().getDate();
                     def.inputDate = null
                 }
                 else {
                     //不然使用input的日期
                     def.Year = parseInt(v[1], 10);
                     def.Month = parseInt(v[3], 10);
                     def.Day = parseInt(v[4], 10);
                     def.inputDate = new Date(def.Year, def.Month - 1, def.Day);
                 }
                 //註冊臨時數據,由於是單例的緣故
                 cp.data( "ctarget" , obj).data( "cpk" , me).data( "indata" , def.inputDate).data( "onReturn" , def.onReturn);
                 //調用規則,返回可選的日期範圍
                 if (def.applyrule && $.isFunction(def.applyrule)) {
                     var rule = def.applyrule.call(obj, obj[0].id);
                     if (rule) {
                         if (rule.startdate) {
                             cp.data( "ads" , rule.startdate);
                         }
                         else {
                             cp.removeData( "ads" );
                         }
                         if (rule.enddate) {
                             cp.data( "ade" , rule.enddate);
                         }
                         else {
                             cp.removeData( "ade" );
                         }
                     }
                 }
                 else {
                     //不存在則刪除限制
                     cp.removeData( "ads" ).removeData( "ade" )
                 }
                 //畫月日曆內容td了
                 writecb();
 
                 $( "#BBIT-DP-T" ).height(cp.height());
                 //獲取顯示依附的對象
                 var t = def.showtarget || obj;
                 //獲取對象的位置
                 var pos = t.offset();
 
                 //獲取對象的高度
                 var height = t.outerHeight();
                 //日期選擇框的位置是依附對象的位置加上自己高度
                 var newpos = { left: pos.left, top: pos.top + height };
                 //如下都是處理窗口邊界問題
                 var w = cp.width();
                 var h = cp.height();
                 var bw = document.documentElement.clientWidth;
                 var bh = document.documentElement.clientHeight;
                 if ((newpos.left + w) >= bw) {
                     newpos.left = bw - w - 2;
                 }
                 if ((newpos.top + h) >= bh) {
                     newpos.top = pos.top - h - 2;
                 }
                 if (newpos.left < 0) {
                     newpos.left = 10;
                 }
                 if (newpos.top < 0) {
                     newpos.top = 10;
                 }
                 //強制默認是月日期視圖
                 $( "#BBIT-DP-MP" ).hide();
                 newpos.visibility = "visible" ;
                 cp.css(newpos); //移動到對應位置並顯示
 
                  $( this ).attr( "isshow" , "1" );
                 //給document註冊單次的click事件,解決打開日期選擇器後,點擊其餘位置,隱藏日期選擇器的問題
                 $(document).one( "click" , function (e) {
                     me.attr( "isshow" , "0" );
                     cp.removeData( "ctarget" ).removeData( "cpk" ).removeData( "indata" );
                     cp.css( "visibility" , "hidden" );
                 });
                     
                 return false ; //組織冒泡
             }

其餘一些代碼都是日期操做的函數,如上月下月等就不作介紹了,你們若是對代碼上又任何問題均可以留言,我必定解答,最後是示例了

第一個示例是老老實實的演示Demo示例,有三種方式,也有調用方式的說明:

http://jscs.cloudapp.net/ControlsSample/dpdemo

第二個示例是我寫的日程管理控件中結合datepicker的應用(你們能夠先看看這個)

http://xuanye.cloudapp.net/

位置是:imageimage 

 

是datepicker在個人創造中的應用,最後若是你以爲這邊文章對你有所幫助,那就點擊一下【推薦】

本文的地址:http://www.cnblogs.com/xuanye/archive/2009/10/27/1590992.html

轉載請保留上面的連接,謝謝

出處:http://www.cnblogs.com/xuanye/archive/2009/10/27/1590992.html

相關文章
相關標籤/搜索