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


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

  首先还是套版化编写jQuery控件的套子:

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

  这样做的好处上篇已经讲过了 ,就不重述了

  接着就是定义默认的参数,已在代码中添加了注释说明这些参数的意义,有几个参数是为了多语言而设置的,如weekName,monthName

01.var def = {
02.            weekStart: 0,//一周开始的是星期几0代表星期天
03.            weekName: ["日", "一", "二", "三", "四", "五", "六"], //星期的格式
04.            monthName: ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"], //月份的格式
05.            monthp: "月",//月的后缀
06.            Year: new Date().getFullYear(), //定义年的变量的初始值
07.            Month: new Date().getMonth() + 1, //定义月的变量的初始值
08.            Day: new Date().getDate(), //定义日的变量的初始值
09.            today: new Date(),//today
10.            btnOk: " 确定 ",//确定按钮的文字
11.            btnCancel: " 取消 ",//取消按钮的文字
12.            btnToday: "今天", //今天按钮的文字
13.            inputDate: null,//无用,只是在代码中会用它存放数据
14.            onReturn: false,//当选择日期后回调的函数
15.            version: "1.0",//版本
16.            applyrule: false, //日期选择规则,可设置可选择的日期范围function(){};return rule={startdate,endate};
17.            showtarget: null, //显示载体,日历展开式所依赖的对象,默认是对象本身
18.            picker: "" //附加点击事件的对象
19.        };
20.    $.extend(def, o);//用传递过来的参数来填充默认
第二部自然是初始化月视图和年月选择视图的HTML了

01.//给日期选择控件一个特殊的ID,获取这个ID的对象,判断如果对象存在,则直接使用
02.// 日期的HTML采用单例,即一个页面上只生成一份HTML
03.  var cp = $("#BBIT_DP_CONTAINER");
04. 
05.        if (cp.length == 0) {
06.            var cpHA = []; //老规矩还是用数组拼接html,最后用innerHTML的方式附加到容器,提升性能
07.            cpHA.push("<div id='BBIT_DP_CONTAINER' class='bbit-dp' style='width:175px;z-index:999;'>");
08.            if ($.browser.msie6) { //如果是IE6弹出层遮盖select
09.                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>');
10.            }
11.            cpHA.push("<table class='dp-maintable' cellspacing='0' cellpadding='0' style='width:175px;'><tbody><tr><td>");
12.            //头哟
13.            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& gt;");
14.            cpHA.push("</td></tr>");
15.            cpHA.push("<tr><td>");
16.            //周
17.            cpHA.push("<table id='BBIT_DP_INNER' class='bbit-dp-inner' cellspacing='0'><thead><tr>");
18.            //生成周
19.            for (var i = def.weekStart, j = 0; j < 7; j++) {
20.                cpHA.push("<th><span>", def.weekName[i], "</span></th>");
21.                if (i == 6) { i = 0; } else { i++; }
22.            }
23.         
24.            .....//省略若干代码
25.            cpHA.push("</tbody></table>");
26.            cpHA.push("</div>");
27.            cpHA.push("</div>");
28. 
29.            var s = cpHA.join("");
30.            $(document.body).append(s); //添加到body中
31.            cp = $("#BBIT_DP_CONTAINER"); //再获取一遍
32. 
33.            initevents(); //初始化事件
34.        }

这里有一个关键点,就是日期的html输出和事件初始化只做一次,因为基本上一页上同时不会打开两个。还有就是生成html中有一些特殊的自定义属性哦,仔细看下就会发现的,这些属性在后面的时间处理中都有很大的作用。那么来看一下事件吧

01.$("#BBIT-DP-TODAY").click(returntoday);//今天按钮的事件
02.         cp.click(returnfalse);//阻止冒泡
03.         $("#BBIT_DP_INNER tbody").click(tbhandler);//给月视图中间body添加click事件而不是给每个td添加
04.         $("#BBIT_DP_LEFTBTN").click(prevm);//上个月
05.         $("#BBIT_DP_RIGHTBTN").click(nextm);//下个月
06.         $("#BBIT_DP_YMBTN").click(showym);//切换到年月视图
07.         $("#BBIT-DP-MP").click(mpclick);//年月视图的点击事件,同样用于分发
08.         $("#BBIT-DP-MP-PREV").click(mpprevy);//上一年
09.         $("#BBIT-DP-MP-NEXT").click(mpnexty);//下一年
10.         $("#BBIT-DP-MP-OKBTN").click(mpok);//ok按钮的事件
11.         $("#BBIT-DP-MP-CANCELBTN").click(mpcancel);//cancel按钮的事件

  给每一个需要点击的元素加上事件哦,这里有两个地方比较特殊,一个是月视图的点击事件,传统的做法就是给每个td都加事件,但是这个时候我的td还没有呢,但是如果在每次生成td的时候来附加事件,那么就由影响性能,所以直接给容器加了点击事件,通过对事件源的判断来分发事件,另外一个年月选择视图,也是和上面一样的逻辑,那么我们就拿月视图的点击事件来分析一下,其实每一个td生成的时候都会注册一个xdate自定义属性 ,来看一下tbhandler函数

01.function tbhandler(e) {
02.            var et = e.target || e.srcElement; //找到事件源
03.            var td = getTd(et); //事件源递归往上找td
04.            if (td == null) {
05.                return false;
06.            }
07.            var $td = $(td);
08.            if (!$(td).hasClass("bbit-dp-disabled")) {//如果不是禁用状态
09.                var s = $td.attr("xdate");//获取td的自定义属性日期数据
10.                var arrs = s.split("-");
11.                cp.data("indata", new Date(arrs[0], parseInt(arrs[1], 10) - 1, arrs[2]));
12.                returndate();//返回日期
13.            }
14.            return false;
15.        }

  所有的日期选择事件初始化好了(一次性的),接着就要给每一个的picker添加点击事件了

01.return $(this).each(function() {
02.            var obj = $(this).addClass("bbit-dp-input");//给input添加样式
03.            var picker = $(def.picker);//获取picker对象
04.            //如果showtarget不为null这将picker注册到input的后面
05.            //否则用户自己处理picker的位置,即picker在页面上本身就已经存在
06.            //大家可以看看示例中1,3调用的区别
07.            def.showtarget == null && obj.after(picker);
08.             
09.            picker.click(function(e) {
10. 
11....//省略代码
12.});

picker的点击事件比较长,单独拿出来讲一下我想比较好,第一个要点是显示隐藏事件的处理,第二个是窗口边缘问题的处理,还有一个就是日期范围规则的处理。

001.function(e) {
002.//获取当前是否显示
003.                var isshow = $(this).attr("isshow");
004.                 
005.                var me = $(this);
006.                //如果显示着,则隐藏,用于处理点击一下picker显示,再点击picker隐藏的逻辑
007.                if (cp.css("visibility") == "visible") {
008.                    cp.css(" visibility", "hidden");
009.                }
010.                //同样是如果显示着
011.                if (isshow == "1") {
012.                    me.attr("isshow", "0");
013.                    //remover临时数据,因为是单例所以要表示当前是哪个input
014.                    cp.removeData("ctarget").removeData("cpk").removeData("indata").removeData("onReturn");
015.                    return false; //阻止冒泡
016.                }
017.                //如果隐藏着,获取input的值
018.                var v = obj.val();
019.                if (v != "") {
020.                    v = v.match(dateReg);//验证一下格式是否正确
021.                }
022.                if (v == null || v == "") {//格式不正确或为空则用当前日期
023.                    def.Year = new Date().getFullYear();
024.                    def.Month = new Date().getMonth() + 1;
025.                    def.Day = new Date().getDate();
026.                    def.inputDate = null
027.                }
028.                else {
029.                    //否则使用input的日期
030.                    def.Year = parseInt(v[1], 10);
031.                    def.Month = parseInt(v[3], 10);
032.                    def.Day = parseInt(v[4], 10);
033.                    def.inputDate = new Date(def.Year, def.Month - 1, def.Day);
034.                }
035.                //注册临时数据,因为是单例的缘故
036.                cp.data("ctarget", obj).data("cpk", me).data("indata", def.inputDate).data("onReturn", def.onReturn);
037.                //调用规则,返回可选的日期范围
038.                if (def.applyrule && $.isFunction(def.applyrule)) {
039.                    var rule = def.applyrule.call(obj, obj[0].id);
040.                    if (rule) {
041.                        if (rule.startdate) {
042.                            cp.data("ads", rule.startdate);
043.                        }
044.                        else {
045.                            cp.removeData("ads");
046.                        }
047.                        if (rule.enddate) {
048.                            cp.data("ade", rule.enddate);
049.                        }
050.                        else {
051.                            cp.removeData("ade");
052.                        }
053.                    }
054.                }
055.                else {
056.                    //不存在则删除限制
057.                    cp.removeData("ads").removeData("ade")
058.                }
059.                //画月日历内容td了
060.                writecb();
061. 
062.                $("#BBIT-DP-T").height(cp.height());
063.                //获取显示依附的对象
064.                var t = def.showtarget || obj;
065.                //获取对象的位置
066.                var pos = t.offset();
067. 
068.                //获取对象的高度
069.                var height = t.outerHeight();
070.                //日期选择框的位置是依附对象的位置加上本身高度
071.                var newpos = { left: pos.left, top: pos.top + height };
072.                //以下都是处理窗口边界问题
073.                var w = cp.width();
074.                var h = cp.height();
075.                var bw = document.documentElement.clientWidth;
076.                var bh = document.documentElement.clientHeight;
077.                if ((newpos.left + w) >= bw) {
078.                    newpos.left = bw - w - 2;
079.                }
080.                if ((newpos.top + h) >= bh) {
081.                    newpos.top = pos.top - h - 2;
082.                }
083.                if (newpos.left < 0) {
084.                    newpos.left = 10;
085.                }
086.                if (newpos.top < 0) {
087.                    newpos.top = 10;
088.                }
089.                //强制默认是月日期视图
090.                $("#BBIT-DP-MP").hide();
091.                newpos.visibility = "visible";
092.                cp.css(newpos); //移动到对应位置并显示
093. 
094.                 $(this).attr("isshow", "1");
095.                //给document注册单次的click事件,解决打开日期选择器后,点击其他位置,隐藏日期选择器的问题
096.                $(document).one("click", function(e) {
097.                    me.attr("isshow", "0");
098.                    cp.removeData("ctarget").removeData("cpk").removeData("indata");
099.                    cp.css("visibility", "hidden");
100.                });
101.                     
102.                return false;//组织冒泡
103.            }

  其他一些代码都是日期操作的函数,如上月下月等就不做介绍了,大家如果对代码上又任何问题都可以留言,我一定解答,最后是示例了

  第一个示例是老老实实的演示Demo示例,有三种方式,也有调用方式的说明:

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

  第二个示例是我写的日程管理控件中结合datepicker的应用(大家可以先看看这个)

  http://xuanye.cloudapp.net/

  位置是

  

  和

   

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


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3