打造基于jQuery的日期选择控件

时间:2023-12-21 14:17:20

终于把jQuery拼写正确了哈,哈哈javascript也是区分大小写的,所以确实不能写错,今天我来和大家分享的是日期选择控件的实现,功能也许不够强大,但是能够满足需求。

我之前也写过(正确的说是改过一个日期选择控件,点击这里查看),看下截图哈,也很酷的,windows风格哦。
打造基于jQuery的日期选择控件

但是也有些问题,第一画日历有点慢,第二兼容性不太好IE Only,第三它不是基于jQuery的哈哈。

那还是老规矩,做之前先看下效果

打造基于jQuery的日期选择控件  打造基于jQuery的日期选择控件

这下是更酷的Ext风格了。
从上图我们可以看出这个控件其实有两个视图一个日期月视图,还有一个是年月选择视图。
1:还是先从HTML入手

日期控件确定HTML其实还是比较简单,因为明摆着是列表的数据格式,当然主要是采用table了。
两个视图分别用两个Div包裹,控制div的显示隐藏即可以切换视图了。完整的HTMl结构大家可以用IEDeveloper看一下Demo的结构,我自己截了一个图
打造基于jQuery的日期选择控件

2:根据HTML和效果图编写CSS

其实因为是Ext风格的,所以直接copy的ext的css和图片。。

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

因为博客园的语法高亮不支持CSS,所以就不贴出来了,给个下载地址吧:

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

所有用到的图片:

打造基于jQuery的日期选择控件打造基于jQuery的日期选择控件打造基于jQuery的日期选择控件

3:搞定了CSS之后呢,就开始编写我们javascript了。

上来就是一个完整代码

+?
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
;(function($) {
    var userAgent = window.navigator.userAgent.toLowerCase();
    $.browser.msie8 = $.browser.msie && /msie 8\.0/i.test(userAgent);
    $.browser.msie7 = $.browser.msie && /msie 7\.0/i.test(userAgent);
    $.browser.msie6 = !$.browser.msie8 && !$.browser.msie7 && $.browser.msie && /msie 6\.0/i.test(userAgent);
    Date.prototype.Format = function(format) {
        var o = {
            "M+": this.getMonth() + 1,
            "d+": this.getDate(),
            "h+": this.getHours(),
            "H+": this.getHours(),
            "m+": this.getMinutes(),
            "s+": this.getSeconds(),
            "q+": Math.floor((this.getMonth() + 3) / 3),
            "w": "0123456".indexOf(this.getDay()),
            "S": this.getMilliseconds()
        };
        if (/(y+)/.test(format)) {
            format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
        }
        for (var k in o) {
            if (new RegExp("(" + k + ")").test(format))
                format = format.replace(RegExp.$1,
          RegExp.$1.length == 1 ? o[k] :
            ("00" + o[k]).substr(("" + o[k]).length));
        }
        return format;
    };
    function DateAdd(interval, number, idate) {
        number = parseInt(number);
        var date;
        if (typeof (idate) == "string") {
            date = idate.split(/\D/);
            eval("var date = new Date(" + date.join(",") + ")");
        }
        if (typeof (idate) == "object") {
            date = new Date(idate.toString());
        }
        switch (interval) {
            case "y": date.setFullYear(date.getFullYear() + number); break;
            case "m": date.setMonth(date.getMonth() + number); break;
            case "d": date.setDate(date.getDate() + number); break;
            case "w": date.setDate(date.getDate() + 7 * number); break;
            case "h": date.setHours(date.getHours() + number); break;
            case "n": date.setMinutes(date.getMinutes() + number); break;
            case "s": date.setSeconds(date.getSeconds() + number); break;
            case "l": date.setMilliseconds(date.getMilliseconds() + number); break;
        }
        return date;
    };
    $.fn.datepicker = function(o) {
        var def = {
            weekStart: 0,
            weekName: ["日", "一", "二", "三", "四", "五", "六"], //星期的格式
            monthName: ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"], //月份的格式
            monthp: "月",
            Year: new Date().getFullYear(), //定义年的变量的初始值
            Month: new Date().getMonth() + 1, //定义月的变量的初始值
            Day: new Date().getDate(), //定义日的变量的初始值
            today: new Date(),
            btnOk: " 确定 ",
            btnCancel: " 取消 ",
            btnToday: "今天",
            inputDate: null,
            onReturn: false,
            version: "1.1",
            applyrule: false, //function(){};return rule={startdate,endate};
            showtarget: null,
            picker: ""
        };
        $.extend(def, o);
        var cp = $("#BBIT_DP_CONTAINER");
        if (cp.length == 0) {
            var cpHA = [];
            cpHA.push("<div id='BBIT_DP_CONTAINER' class='bbit-dp' style='width:175px;z-index:999;'>");
            if ($.browser.msie6) {
                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("</tr></thead>");
            //生成tBody,需要重新生成的
            cpHA.push("<tbody></tbody></table>");
            //生成tBody结束
            cpHA.push("</td></tr>");
            cpHA.push("<tr><td class='bbit-dp-bottom' align='center'><button id='BBIT-DP-TODAY'>", def.btnToday, "</button></td></tr>");
            cpHA.push("</tbody></table>");
            //输出下来框
            cpHA.push("<div id='BBIT-DP-MP' class='bbit-dp-mp'  style='z-index:auto;'><table id='BBIT-DP-T' style='width: 175px; height: 193px' border='0' cellspacing='0'><tbody>");
            cpHA.push("<tr>");
            //1月,7月 按钮两个
            cpHA.push("<td class='bbit-dp-mp-month' xmonth='0'><a href='javascript:void(0);'>", def.monthName[0], "</a></td><td class='bbit-dp-mp-month bbit-dp-mp-sep' xmonth='6'><a href='javascript:void(0);'>", def.monthName[6], "</a></td><td class='bbit-dp-mp-ybtn' align='middle'><a id='BBIT-DP-MP-PREV' class='bbit-dp-mp-prev'></a></td><td class='bbit-dp-mp-ybtn' align='middle'><a id='BBIT-DP-MP-NEXT' class='bbit-dp-mp-next'></a></td>");
            cpHA.push("</tr>");
            cpHA.push("<tr>");
            cpHA.push("<td class='bbit-dp-mp-month' xmonth='1'><a href='javascript:void(0);'>", def.monthName[1], "</a></td><td class='bbit-dp-mp-month bbit-dp-mp-sep' xmonth='7'><a href='javascript:void(0);'>", def.monthName[7], "</a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td>");
            cpHA.push("</tr>");
            cpHA.push("<tr>");
            cpHA.push("<td class='bbit-dp-mp-month' xmonth='2'><a href='javascript:void(0);'>", def.monthName[2], "</a></td><td class='bbit-dp-mp-month bbit-dp-mp-sep' xmonth='8'><a href='javascript:void(0);'>", def.monthName[8], "</a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td>");
            cpHA.push("</tr>");
            cpHA.push("<tr>");
            cpHA.push("<td class='bbit-dp-mp-month' xmonth='3'><a href='javascript:void(0);'>", def.monthName[3], "</a></td><td class='bbit-dp-mp-month bbit-dp-mp-sep' xmonth='9'><a href='javascript:void(0);'>", def.monthName[9], "</a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td>");
            cpHA.push("</tr>");
            cpHA.push("<tr>");
            cpHA.push("<td class='bbit-dp-mp-month' xmonth='4'><a href='javascript:void(0);'>", def.monthName[4], "</a></td><td class='bbit-dp-mp-month bbit-dp-mp-sep' xmonth='10'><a href='javascript:void(0);'>", def.monthName[10], "</a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td>");
            cpHA.push("</tr>");
            cpHA.push("<tr>");
            cpHA.push("<td class='bbit-dp-mp-month' xmonth='5'><a href='javascript:void(0);'>", def.monthName[5], "</a></td><td class='bbit-dp-mp-month bbit-dp-mp-sep' xmonth='11'><a href='javascript:void(0);'>", def.monthName[11], "</a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td><td class='bbit-dp-mp-year'><a href='javascript:void(0);'></a></td>");
            cpHA.push("</tr>");
            cpHA.push("<tr class='bbit-dp-mp-btns'>");
            cpHA.push("<td colspan='4'><button id='BBIT-DP-MP-OKBTN' class='bbit-dp-mp-ok'>", def.btnOk, "</button><button id='BBIT-DP-MP-CANCELBTN' class='bbit-dp-mp-cancel'>", def.btnCancel, "</button></td>");
            cpHA.push("</tr>");
            cpHA.push("</tbody></table>");
            cpHA.push("</div>");
            cpHA.push("</div>");
            var s = cpHA.join("");
            $(document.body).append(s);
            var cp = $("#BBIT_DP_CONTAINER");
            initevents();
        }
        function initevents() {
            //1 today btn;
            $("#BBIT-DP-TODAY").click(returntoday);
            cp.click(returnfalse);
            $("#BBIT_DP_INNER tbody").click(tbhandler);
            $("#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);
            $("#BBIT-DP-MP-CANCELBTN").click(mpcancel);
        }
        function mpcancel() {
            $("#BBIT-DP-MP").animate({ top: -193 }, { duration: 200, complete: function() { $("#BBIT-DP-MP").hide(); } });
            return false;
        }
        function mpok() {
            def.Year = def.cy;
            def.Month = def.cm + 1;
            def.Day = 1;
            $("#BBIT-DP-MP").animate({ top: -193 }, { duration: 200, complete: function() { $("#BBIT-DP-MP").hide(); } });
            writecb();
            return false;
        }
        function mpprevy() {
            var y = def.ty - 10
            def.ty = y;
            rryear(y);
            return false;
        }
        function mpnexty() {
            var y = def.ty + 10
            def.ty = y;
            rryear(y);
            return false;
        }
        function rryear(y) {
            var s = y - 4;
            var ar = [];
            for (var i = 0; i < 5; i++) {
                ar.push(s + i);
                ar.push(s + i + 5);
            }
            $("#BBIT-DP-MP td.bbit-dp-mp-year").each(function(i) {
                if (def.Year == ar[i]) {
                    $(this).addClass("bbit-dp-mp-sel");
                }
                else {
                    $(this).removeClass("bbit-dp-mp-sel");
                }
                $(this).html("<a href='javascript:void(0);'>" + ar[i] + "</a>").attr("xyear", ar[i]);
            });
        }
        function mpclick(e) {
            var panel = $(this);
            var et = e.target || e.srcElement;
            var td = getTd(et);
            if (td == null) {
                return false;
            }
            if ($(td).hasClass("bbit-dp-mp-month")) {
                if (!$(td).hasClass("bbit-dp-mp-sel")) {
                    var ctd = panel.find("td.bbit-dp-mp-month.bbit-dp-mp-sel");
                    if (ctd.length > 0) {
                        ctd.removeClass("bbit-dp-mp-sel");
                    }
                    $(td).addClass("bbit-dp-mp-sel")
                    def.cm = parseInt($(td).attr("xmonth"));
                }
            }
            if ($(td).hasClass("bbit-dp-mp-year")) {
                if (!$(td).hasClass("bbit-dp-mp-sel")) {
                    var ctd = panel.find("td.bbit-dp-mp-year.bbit-dp-mp-sel");
                    if (ctd.length > 0) {
                        ctd.removeClass("bbit-dp-mp-sel");
                    }
                    $(td).addClass("bbit-dp-mp-sel")
                    def.cy = parseInt($(td).attr("xyear"));
                }
            }
            return false;
        }
        function showym() {
            var mp = $("#BBIT-DP-MP");
            var y = def.Year;
            def.cy = def.ty = y;
            var m = def.Month - 1;
            def.cm = m;
            var ms = $("#BBIT-DP-MP td.bbit-dp-mp-month");
            for (var i = ms.length - 1; i >= 0; i--) {
                var ch = $(ms[i]).attr("xmonth");
                if (ch == m) {
                    $(ms[i]).addClass("bbit-dp-mp-sel");
                }
                else {
                    $(ms[i]).removeClass("bbit-dp-mp-sel");
                }
            }
            rryear(y);
            mp.css("top", -193).show().animate({ top: 0 }, { duration: 200 });
        }
        function getTd(elm) {
            if (elm.tagName.toUpperCase() == "TD") {
                return elm;
            }
            else if (elm.tagName.toUpperCase() == "BODY") {
                return null;
            }
            else {
                var p = $(elm).parent();
                if (p.length > 0) {
                    if (p[0].tagName.toUpperCase() != "TD") {
                        return getTd(p[0]);
                    }
                    else {
                        return p[0];
                    }
                }
            }
            return null;
        }
        function tbhandler(e) {
            var et = e.target || e.srcElement;
            var td = getTd(et);
            if (td == null) {
                return false;
            }
            var $td = $(td);
            if (!$(td).hasClass("bbit-dp-disabled")) {
                var s = $td.attr("xdate");
                var arrs = s.split("-");
                cp.data("indata", new Date(arrs[0], parseInt(arrs[1], 10) - 1, arrs[2]));
                returndate();
            }
            return false;
        }
        function returnfalse() {
            return false;
        }
        function prevm() {
            if (def.Month == 1) {
                def.Year--;
                def.Month = 12;
            }
            else {
                def.Month--
            }
            writecb();
            return false;
        }
        function nextm() {
            if (def.Month == 12) {
                def.Year++;
                def.Month = 1;
            }
            else {
                def.Month++
            }
            writecb();
            return false;
        }
        function returntoday() {
            cp.data("indata", new Date());
            returndate();
        }
        function returndate() {
            var ct = cp.data("ctarget");
            var ck = cp.data("cpk");
            var re = cp.data("onReturn");
            var ndate = cp.data("indata")
            var ads = cp.data("ads");
            var ade = cp.data("ade");
            var dis = false;
            if (ads && ndate < ads) {
                dis = true;
            }
            if (ade && ndate > ade) {
                dis = true;
            }
            if (dis) {
                return;
            }
            if (re && jQuery.isFunction(re)) {
                re.call(ct[0], cp.data("indata"));
            }
            else {
                ct.val(cp.data("indata").Format("yyyy-MM-dd"));
            }
            ck.attr("isshow", "0");
            cp.removeData("ctarget").removeData("cpk").removeData("indata").removeData("onReturn")
            .removeData("ads").removeData("ade");
            cp.css("visibility", "hidden");
            ct = ck = null;
        }
        function writecb() {
            var tb = $("#BBIT_DP_INNER tbody");
            $("#BBIT_DP_YMBTN").html(def.monthName[def.Month - 1] + def.monthp + " " + def.Year);
            var firstdate = new Date(def.Year, def.Month - 1, 1);
            var diffday = def.weekStart - firstdate.getDay();
            var showmonth = def.Month - 1;
            if (diffday > 0) {
                diffday -= 7;
            }
            var startdate = DateAdd("d", diffday, firstdate);
            var enddate = DateAdd("d", 42, startdate);
            var ads = cp.data("ads");
            var ade = cp.data("ade");
            var bhm = [];
            var tds = def.today.Format("yyyy-MM-dd");
            var indata = cp.data("indata");
            var ins = indata != null ? indata.Format("yyyy-MM-dd") : "";
            for (var i = 1; i <= 42; i++) {
                if (i % 7 == 1) {
                    bhm.push("<tr>");
                }
                var ndate = DateAdd("d", i - 1, startdate);
                var tdc = [];
                var dis = false;
                if (ads && ndate < ads) {
                    dis = true;
                }
                if (ade && ndate > ade) {
                    dis = true;
                }
                if (ndate.getMonth() < showmonth) {
                    tdc.push("bbit-dp-prevday");
                }
                else if (ndate.getMonth() > showmonth) {
                    tdc.push("bbit-dp-nextday");
                }
                if (dis) {
                    tdc.push("bbit-dp-disabled");
                }
                else {
                    tdc.push("bbit-dp-active");
                }
                var s = ndate.Format("yyyy-MM-dd");
                if (s == tds) {
                    tdc.push("bbit-dp-today");
                }
                if (s == ins) {
                    tdc.push("bbit-dp-selected");
                }
                bhm.push("<td class='", tdc.join(" "), "' title='", ndate.Format("yyyy-MM-dd"), "' xdate='", ndate.Format("yyyy-M-d"), "'><a href='javascript:void(0);'><em><span>", ndate.getDate(), "</span></em></a></td>");
                if (i % 7 == 0) {
                    bhm.push("</tr>");
                }
            }
            tb.html(bhm.join(""));
        }
        var dateReg = /^(\d{1,4})(-|\/|.)(\d{1,2})\2(\d{1,2})$/;
        return $(this).each(function() {
            var obj = $(this).addClass("bbit-dp-input");
            var picker = $(def.picker);
            def.showtarget == null && obj.after(picker);
            picker.click(function(e) {
                var isshow = $(this).attr("isshow");
                //先隐藏
                var me = $(this);
                if (cp.css("visibility") == "visible") {
                    cp.css(" visibility", "hidden");
                }
                if (isshow == "1") {
                    me.attr("isshow", "0");
                    cp.removeData("ctarget").removeData("cpk").removeData("indata").removeData("onReturn");
                    return false;
                }
                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 {
                    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")
                }
                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);
                //cp.show();
                $(this).attr("isshow", "1");
                $(document).one("click", function(e) {
                    me.attr("isshow", "0");
                    cp.removeData("ctarget").removeData("cpk").removeData("indata");
                    cp.css("visibility", "hidden");
                });
                return false;
            });
        });
    };
})(jQuery);

那接着就是分析一下实现的主要过程和一些注意的要点:

首先还是套版化编写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自定义属性 打造基于jQuery的日期选择控件 ,来看一下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/

位置是:打造基于jQuery的日期选择控件打造基于jQuery的日期选择控件

是datepicker在我的创造中的应用,最后如果你觉得这边文章对你有所帮助,那就点击一下【推荐】

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

转载请保留上面的链接,谢谢

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