独醉江湖的硅行之秀http://www.guixing.info/dzjh.html 设为首页加入收藏夹RSS订阅推荐给好友 今天是:2019年11月22日星期五
>文章列表[原创]>创建样式可控的javascript日历控件[二]

创建样式可控的javascript日历控件[二]

摘要:接上一篇:创建样式可控的javascript日历控件(1)在上一篇中通过截图展示了日历控件的最终模样以及生成的日历表格结构和javascript代码的结构,本文将以实现控件的几个核心方法为主,如根据日期创建日历表格和对日历表格的事件处理。回顾上一篇的javascript代码的结构,如下:JavaSc……

接上一篇:创建样式可控的javascript日历控件[一]

在上一篇中通过截图展示了日历控件的最终模样以及生成的日历表格结构和javascript代码的结构,本文将以实现控件的几个核心方法为主,如根据日期创建日历表格和对日历表格的事件处理。

回顾上一篇的javascript代码的结构,如下:

JavaScript Code复制内容到剪贴板
  1. var Calendar = function(_date) {   
  2.     var newCalendar = function(date) {   
  3.         //日历对象的具体实现   
  4.     };   
  5.     return new newCalendar(_date)   
  6. };  

我们将在newCalendar中完成日历控件的创建和封装,生成的日历对象从呈现上来说就是一个表格,可以简单来分成这么几个步骤:处理参数=>生成表格=>事件处理(年份和月份的翻转,日期的点击,皮肤的设置以及控件的放置等)。

处理参数和生成表格在同一个函数中完成,函数为createTable(date),年份和月份的翻转其实是调用createTable函数生成新的日历表格,然后对新旧表格的内容进行替换(是替换表格内容而不是直接替换表格),为调用方便,对于表格内容的替换操作单独写成一个resetTable(Table1,Table2)函数,至此,由createTable(date)和resetTable(Table1,Table2)两个函数来完成日历表格的创建和翻转,日历的雏形就算完成了。

下面开始来实现这两个函数,createTable(date)函数算是主函数,resetTable(Table1,Table2)是辅助型的,所以在实现createTable(date)函数之前先说一下涉及到的一些日期处理方法:

  1. 初始化一个Date对象
  2. 用正则匹配参数并分组捕获年月日的对应数值,如果参数符合日期模式则通过Date(year,month,day)的方式初始化日期,其中month取值0-11
  3. 平年和闰年的判断:var leapYear = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? true: false;
  4. 对应的月份天数获取,大月31天,小月30天,2月份根据平年或闰年分别为28天火29天:var days = [31, (leapYear ? 29: 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
  5. 关于中文星期的获取,我们知道javascript的Date对象提供了一个getDay()的函数来获取日期对应的星期,其返回值为0-6,0表示星期天,1表示星期一,以此类推,我们可以这样来获得对应的中文星期名:var weekDayNames=["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]; var weekDayName=weekDayNames[Date.getDay()];
  6. 让生成的日期和星期对应:我们的表格是七列的模式,分别对应一个星期的七天,所以表格头的星期生成是很简单的,只要循环输出前面的weekDayNames数组就行,而中间的日期部分的生成要和星期对应也只要获取到那个月份第一天对应的星期数并对应好就可以了,七列一换行,后面的自然都能一一对应上

好了,好像没什么可说的了,看根据日期创建表格的函数代码吧:

JavaScript Code复制内容到剪贴板
  1. var createTable = function(date) {//根据日期创建表格   
  2.     var now = new Date();   
  3.     if (date !== null && /^(\d{4})[-]?(\d{1,2})[-]?(\d{1,2}).*/.exec(date)) {   
  4.         var y = parseInt(RegExp.$1, 10),   
  5.         m = parseInt(RegExp.$2, 10),   
  6.         d = parseInt(RegExp.$3, 10);   
  7.         now = new Date(y, m - 1, d)   
  8.     }   
  9.     var year = now.getFullYear(),month = now.getMonth(),day = now.getDate(),weekDay = now.getDay();   
  10.        
  11.     var weekDayNames = ["星期天""星期一""星期二""星期三""星期四""星期五""星期六"];//中文星期名   
  12.     var weekDayName = weekDayNames[weekDay];//当前日期对应的中文星期名   
  13.     var leapYear = (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) ? truefalse;//平年或闰年判断   
  14.     var days = [31, (leapYear ? 29: 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];//当前月份的天数   
  15.        
  16.     var table = document.createElement("table");   
  17.     var thead = document.createElement("thead");   
  18.     var tbody = document.createElement("tbody");   
  19.     var tfoot = document.createElement("tfoot");   
  20.     table.appendChild(thead);   
  21.     table.appendChild(tbody);   
  22.     table.appendChild(tfoot);   
  23.        
  24.     //thead部分   
  25.     var h_tr = document.createElement("tr"),   
  26.     h_selected = false;   
  27.     for (var i = 0; i < 7; i++) {   
  28.         var h_th = document.createElement("th");   
  29.         h_th.innerHTML = weekDayNames[i];   
  30.         if (weekDay === i) {   
  31.             h_th.className = "selected";   
  32.             h_selected = true  
  33.         }   
  34.         h_tr.appendChild(h_th)   
  35.     }   
  36.     thead.appendChild(h_tr);   
  37.        
  38.     //tbody部分   
  39.     var begin = new Date(year, month, 1).getDay();//获取当前年份月份的第一天对应的星期   
  40.     var must_tds = days + begin;//必需的单元格数量   
  41.     var trs = must_tds % 7 === 0 ? must_tds / 7: Math.floor(must_tds / 7) + 1;//必需的行数   
  42.     var today = 1, x = 1, end = days + begin;   
  43.     for (var i = 0; i < trs; i++) {   
  44.         var tr = document.createElement("tr");   
  45.         for (var j = 0; j < 7; j++) {   
  46.             var td = document.createElement("td");   
  47.             if (x > begin && x <= end) {   
  48.                 td.innerHTML = today;   
  49.                 if (today === day) {   
  50.                     td.className = "selected"  
  51.                 }   
  52.                 td.setAttribute("e""day");//事件处理标识   
  53.                 today++   
  54.             } else {   
  55.                 td.innerHTML = " "  
  56.             }   
  57.             x++;   
  58.             tr.appendChild(td)   
  59.         }   
  60.         tbody.appendChild(tr)   
  61.     }   
  62.        
  63.     //tfoot部分   
  64.     var f_tr = document.createElement("tr");   
  65.     for (var i = 0; i < 5; i++) {   
  66.         var f_th = document.createElement("th");   
  67.         switch (i) {   
  68.         case 0:   
  69.             f_th.innerHTML = "<<年";   
  70.             f_th.setAttribute('e''preYear');//事件处理标识   
  71.             f_th.style.width = "14%";   
  72.             break;   
  73.         case 1:   
  74.             f_th.innerHTML = "<月";   
  75.             f_th.setAttribute('e''preMonth');//事件处理标识   
  76.             f_th.style.width = "14%";   
  77.             break;   
  78.         case 2:   
  79.             f_th.innerHTML = year + "年" + (month + 1) + "月" + day + "日";   
  80.             f_th.className = "selected";   
  81.             f_th.colSpan = "3";   
  82.             break;   
  83.         case 3:   
  84.             f_th.innerHTML = "月>";   
  85.             f_th.setAttribute('e''nextMonth');//事件处理标识   
  86.             f_th.style.width = "14%";   
  87.             break;   
  88.         case 4:   
  89.             f_th.innerHTML = "年>>";   
  90.             f_th.setAttribute('e''nextYear');//事件处理标识   
  91.             f_th.style.width = "14%";   
  92.             break  
  93.         }   
  94.         f_tr.appendChild(f_th)   
  95.     }   
  96.     tfoot.appendChild(f_tr);   
  97.        
  98.     return table   
  99. };  

如果只是显示一下今天是某年某月某日的话,单这个函数就已经够用了!不过离原先的目标还有很大一段距离,还需要进一步的完善。表格已经创建出来了,也就是日历控件有了一个雏形,这个表格是控件的核心,后面的事情都将围绕着这个表格转。

既然表格出来了,如果只是摆着就有违初衷了!有了形体后还应该要赐予它一点应变的能力,呵呵。我们下面开始给它绑定事件处理,在绑定事件处理之前有必要强调一下:这个表格是newCalendar的一个成员或者说是属性——在我们创建表格的时候是在newCalendar中通过this.table=createTable(date);这样的形势创建的,所以绑定事件的时候也自然是this.table.onclick=function(e){…………};这样的形式。

下面就来看一下this.table.onclick函数:

JavaScript Code复制内容到剪贴板
  1. //var isObj = this;//引用this(this关键字指向的是当前对象,如果进入子函数后将不能再通过this关键字访问到该"this",所以用变量isObj对其进行引用)   
  2.   
  3. this.table = createTable(date);//创建日历表格   
  4. this.table.onclick = function(e) {//日历表格事件处理   
  5.     e = e || window.event;   
  6.     var ele = e.srcElement || e.target;//得到触发事件的对象(e.target是针对火狐浏览器的)   
  7.     var atr = ele.nodeType === 1 ? ele.getAttribute("e") : '';//得到创建表格时的自定义属性‘e’   
  8.     //根据属性‘e’的值做相应处理   
  9.     switch (atr) {   
  10.     case 'day'://日期   
  11.         callback_fun ? exec_callback_fun(ele) : '';//如果用户设置有回调函数则执行回调函数   
  12.         break;   
  13.     case 'preYear'://上一年   
  14.         var tds = isObj.table.getElementsByTagName("tbody")[0].getElementsByTagName("td");   
  15.         var day = (function() {   
  16.             for (var i = 0; i < tds.length; i++) {   
  17.                 if (tds[i].className === "selected") {   
  18.                     return tds[i].innerHTML   
  19.                 }   
  20.             }   
  21.         })();   
  22.         var arr = isObj.table.getElementsByTagName("tfoot")[0].getElementsByTagName("th")[2].innerHTML.match(/\d+/g);   
  23.         arr[0] = parseInt(arr[0], 10) - 1;   
  24.         arr[2] = day;   
  25.         resetTable(isObj.table, createTable(arr.join('-')));//重置表格内容   
  26.         break;   
  27.     case 'nextYear'://下一年   
  28.         var tds = isObj.table.getElementsByTagName("tbody")[0].getElementsByTagName("td");   
  29.         var day = (function() {   
  30.             for (var i = 0; i < tds.length; i++) {   
  31.                 if (tds[i].className === "selected") {   
  32.                     return tds[i].innerHTML   
  33.                 }   
  34.             }   
  35.         })();   
  36.         var arr = isObj.table.getElementsByTagName("tfoot")[0].getElementsByTagName("th")[2].innerHTML.match(/\d+/g);   
  37.         arr[0] = parseInt(arr[0], 10) + 1;   
  38.         arr[2] = day;   
  39.         resetTable(isObj.table, createTable(arr.join('-')));//重置表格内容   
  40.         break;   
  41.     case 'preMonth'://上个月   
  42.         var tds = isObj.table.getElementsByTagName("tbody")[0].getElementsByTagName("td");   
  43.         var day = (function() {   
  44.             for (var i = 0; i < tds.length; i++) {   
  45.                 if (tds[i].className === "selected") {   
  46.                     return tds[i].innerHTML   
  47.                 }   
  48.             }   
  49.         })();   
  50.         var arr = isObj.table.getElementsByTagName("tfoot")[0].getElementsByTagName("th")[2].innerHTML.match(/\d+/g);   
  51.         arr[1] = parseInt(arr[1], 10) - 1;   
  52.         arr[2] = day;   
  53.         resetTable(isObj.table, createTable(arr.join('-')));//重置表格内容   
  54.         break;   
  55.     case 'nextMonth'://下个月   
  56.         var tds = isObj.table.getElementsByTagName("tbody")[0].getElementsByTagName("td");   
  57.         var day = (function() {   
  58.             for (var i = 0; i < tds.length; i++) {   
  59.                 if (tds[i].className === "selected") {   
  60.                     return tds[i].innerHTML   
  61.                 }   
  62.             }   
  63.         })();   
  64.         var arr = isObj.table.getElementsByTagName("tfoot")[0].getElementsByTagName("th")[2].innerHTML.match(/\d+/g);   
  65.         arr[1] = parseInt(arr[1], 10) + 1;   
  66.         arr[2] = day;   
  67.         resetTable(isObj.table, createTable(arr.join('-')));//重置表格内容   
  68.         break  
  69.     }   
  70. };  

上面的代码是在日历表格被点击时得到触发事件的对象,然后根据对象的"e"属性值进行相应的处理,"e"是在创建表格时设置的。这里有5个处理选择分别是:上一年、下一年、上个月、下个月、日期的点击,前4个的操作基本上是一样的,都是先处理日期然后根据日期创建表格而后用resetTable(oldTable,newTable)函数进行表格的内容替换,而日期的点击处理用的是回调函数(如果用户没有设置回调函数则不作如何处理)。下面是resetTable(oldTable,newTable)函数:

JavaScript Code复制内容到剪贴板
  1. var resetTable = function(o, n) {////重置表格内容(切换年份或月份)   
  2.     o.removeChild(o.getElementsByTagName("thead")[0]);   
  3.     o.removeChild(o.getElementsByTagName("tbody")[0]);   
  4.     o.removeChild(o.getElementsByTagName("tfoot")[0]);   
  5.     o.appendChild(n.getElementsByTagName("thead")[0]);   
  6.     o.appendChild(n.getElementsByTagName("tbody")[0]);   
  7.     o.appendChild(n.getElementsByTagName("tfoot")[0])   
  8. };  

这个函数比较简单,仅对表格的内容作替换(如果直接替换表格的话之前的事件处理就丢失了——表格对象的引用变了)。下面看一下日期的点击处理:

JavaScript Code复制内容到剪贴板
  1. var callback_fun = null;//用户的回调函数(如果用户设置了日期点击的回调函数则将其保存到该变量中)   
  2. var exec_callback_fun = function(ele) {//执行用户的回调函数然后移除表格   
  3.   var date = getdate(ele);   
  4.   callback_fun(date);//执行用户的回调函数   
  5.   var o = ele.parentNode.parentNode.parentNode;   
  6.   o.parentNode.removeChild(o);//移除日历表格   
  7.   isObj = null  
  8. };  

至此,日历控件的主要处理函数算是完成了。下面将说说让用户可以设置日期点击回调函数和设置表格皮肤等的实现,代码很简单,就直接贴代码了:

JavaScript Code复制内容到剪贴板
  1. this.appendTo = function(id) {//将日历添加到某节点   
  2.     var o = typeof(id) === "string" ? document.getElementById(id) : id;   
  3.     if (o === window || o === document) {   
  4.         o = document.body   
  5.     }   
  6.     o = o ? o: document.body;   
  7.     if (this.table) {   
  8.         o.appendChild(this.table)   
  9.     };   
  10.     return this;   
  11. };   
  12. this.clickDay = function(callback) {//接收并保存用户设置的回调函数   
  13.     callback_fun = callback;//保存到callback_fun   
  14.     return this;   
  15. };   
  16. this.setSkin = function(cla){//设置皮肤(亦即给表格设置class)   
  17.     this.table.className=cla;   
  18.     return this;   
  19. };  

这里没每个方法都返回this是为了实现链式调用(对对象操作完成之后返回对象本身即可实现链式调用)。

日历控件创建完毕,我们先写个皮肤样式测试来测试一下,来一个灰色调的:

CSS Code复制内容到剪贴板
  1. .grayCalendar{width:300pxbackground:#fffline-height:25pxborder:solid 1px #666;}   
  2. .grayCalendar thead{background:#666border:solid 1px #666border-collapse:collapseborder-spacing:1px;}   
  3. .grayCalendar thead th{text-align:centerbackground:#555color:#ffffont-size:12pxfont-weight:normal;}   
  4. .grayCalendar tbody td{text-align:centerbackground:#999border:solid 1px #000color:#fffcursor:pointer;}   
  5. .grayCalendar tbody td:hover{background:#ffccolor:#00fborder:solid 1px #f00;}   
  6. .grayCalendar tfoot{background:#000;}   
  7. .grayCalendar tfoot th{text-align:centerbackground:#555color:#ffffont-size:12px;}   
  8. .grayCalendar tfoot th span{display:blockpadding:0pxmargin:0pxcursor:pointer;}   
  9. .grayCalendar tfoot th span:hover{color:#00f;}   
  10. .grayCalendar thead .selected,.grayCalendar tbody .selected,.grayCalendar tfoot .selected{background:#ff0border:solid 1px #f00color:#00f;}  

应用示例:

XML/HTML Code复制内容到剪贴板
  1. <div id="Calendar"></div>   
  2. <script type="text/javascript">   
  3. /*示例1:没有日期参数*/  
  4. var e=Calendar();//创建日历   
  5. e.appendTo('Calendar');//将日历添加到id=Calendar的div中   
  6. e.setSkin('grayCalendar');//设置皮肤   
  7. e.clickDay(function(date){//设置日期点击回调函数   
  8.   alert(date);   
  9. });   
  10. /*示例2:有日期参数且采用链式写法*/  
  11. Calendar('2025-3-2').appendTo('Calendar').setSkin('grayCalendar').clickDay(function(date){alert(date);});   
  12. </script>  

运行结果如图:

到此结束,完整代码下载可以在我的“流程组件”中找到。如果觉得有用,欢迎评论或留言交流!

《创建样式可控的javascript日历控件[二]》 独醉江湖[原创] 阅读[4667] 评论[5] 标签:日期控件 控件 js javascript 链式调用 封装 js控件
这是留给你的位置,说出你的真知灼见吧![我要评论]
1[游客]评论[2014-07-04]:晕,要积分的啊
2[游客]评论[2013-06-08]:组件化?原来这玩意也不难嘛
3[游客]评论[2013-06-01]:额……8错,偶也写个来玩玩,呵呵
4[游客]评论[2013-04-30]:总算明白明白了:对对象操作完成之后返回对象本身即可实现链式调用
        (()__(()
        /       \ 
       ( /    \  \
        \ o o    /
        (_()_)__/ \
       / _,==.____ \
      (   |--|      )
      /\_.|__|'-.__/\_
     / (        /     \ 
     \  \      (      /
      )  '._____)    /
   (((____.--(((____/
5[游客]评论[2013-04-14]:这个javascript日历控件基本可以满足我的需求了,呵呵!^_^赞一个
<<<1>>>
>

随机推荐

独醉江湖[积分:116分]

活跃度:

注册时间:2012-08-12

累计访问量:3615人次

Ta的主页Ta的简历给Ta留言
登录注册

原创文章列表页
>javascript实现智能机上触摸切换图片的网页效果
>ASP的正则表达式应用
>创建样式可控的javascript日历控件[二]
>创建样式可控的javascript日历控件[一]
>10个不常用的HTML标签
>javascript数组操作之移动数组元素
>通过prototype扩展Array对象实现数组去重
>利用ajax实现简单的邮箱采集器[二]
>利用ajax实现简单的邮箱采集器[一]
>javascript自定义标签选择器[三]
转载文章列表页
>认识Web开发中Js的setCapture和releaseCapture
>提高你的JavaScript 开发规范认识
>如何成为一名优秀的web前端工程师
>Javascript 的4种异步编程方法
>网页设计中的分页交互设计
>如何让页面跑的更快(有效缩短页面的渲染时间)
>Web前端工程师必知的技能知识
>函数式JavaScript高级编程
>优秀的JavaScript模块是怎样炼成的
>认识Javascript里的Json
收藏文章列表页
>Mysql存储过程中临时表的建立及游标遍历
>关于网页设计中的色彩搭配与应用
>网页设计中的平面构成
>国内常用四大web应用编程介绍及优缺点比较
>CSS知识要点介绍
>网络数据采集生涯趣谈
>网页制作中需要权衡的页面效果与seo效果
>web开发中如何更合理的应用jQuery
>网站用户体验设计须知
>js[原生javascript]浮动层智能判断上下边界
Copyright © 2012 guixing.info 版权所有 滇ICP备07500776号-2