那接着就是分析一下实现的主要过程和一些注意的要点:
首先还是套版化编写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='向前一个月'> </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='向后一个月'> </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在我的创造中的应用,最后如果你觉得这边文章对你有所帮助,那就点击一下【推荐】?