[javascript]简单 方便 易折腾的日历控件,纯javascript支持链式语法,核心代码只有5行

又重复造了个轮子,重复造轮子当然要有优点要不就没有存在价值。使用简单,方便。只要5行代码就可生成年历。

input date已经是一个原生控件opera和chrome已经支持,日历控件逻辑比较复杂,要做到尽善尽美也是不容易的,也是比较锻炼编码的,所以学习意义大于实际意义。而且这个控件也是多年心愿,最近有时间写写停停,终于坚持下来就拿来和大家分享了。

 

 

传送门

 

特点

1.此日历插件特点在于简单易用,要保证功能实现最低要求一个参数。

2.个性化配置有强大的自定义事件和多个个性化参数可选。

3.采用原型继承,扩展派生非常方便。

4.跨浏览器,保证可用性。

5.采用表格做载体,无样式也可以正常使用功能。

6.缓存,已生成月份数据。使数据持久化,减少计算。

7.无样式支持,功能依然健在。

应用展示

a.

b.

c.

 

技术总结

1.主要难点不是日期算法,而是select控件和表格所带来的问题。select和表格都有一套自己的dom api,来操作和访问。尤其是生成日历table的算法非了一些时间,而且ie浏览器上。innerHTML属性,table tbody tfoot tr都是只读的,所以对技术选型有一些干扰。中间使用了insertRow这样的方法未果,采用分辨浏览器采用不同方案也行不通后,过段采用整个table都用拼字符串的方式。虽然效率不一定比生成dom节点存入变量修改高,但是结果却是最好的。

2.select主要问题在于序号和长度差,要访问selectedIndex,设置select的值都要小心这个变化。

3.Date对象的序号问题,年 日都是从1开始,月份是从0开始,这些差别和人类习惯的处理带来一定成本。

可见初期,技术储备和技术选型的重要性。

其实日期核心算法只有5行代码而已,想要生成一个可用的日期控件20行内代码足够,由于和日期控件相关的控件出来带来了大量代码。

 

核心代码

 

1。计算某个月有多少天,2012.6月到底有多少天呢?我们要是知道6月最后一天是多少号,不就知道6月有多少天了吗。

new Date('2012,6,0').getDate();最简单最短 //chrome不支持用字符串new Date('2012,6,0')格式创建日期, 但支持new Date('2012','6','0');这点要注意 而safari没有问题非常诡异

通用的

(new Date(+(new Date(2012, 7, 1)) - 86400000)).getDate();

下个月的一号减去一天,就是当月最后一天

 

2.知道了当月有多少天还不行,要知道当月1号是要放在什么位置,如果知道1号是星期几不就可以知道1号在什么位置了吗。

new Date(2012, 7,1).getDay();

 

3.生成一个月的日历,代码很简单只有5行

for (var i = 0; i < row; i++) {
  html.push('</tr>');
   for (var j = 0; j < 7; j++) {
      html.push((cell-- <= offset && days > 0) ? ('<td ' + (that.Date > new Date(y, m, days + 1) ? 'class="oldDay"' : '') + (y === that.Year && m === that.Month && days === that.Day ? 'class="currentDay"' : '') + ' title="'+y+that.style+(m+1)+that.style+days+'">' + (days--) + '</td>') : '<td></td>');
   }
   html.push('<tr>');
}

大家可能要怀疑为什么先写的是 </tr>结束标签,开始生成日历的时候采用的是倒序循环,用li标签,后面发现无样式时不能使用,所以改用table但这一方式保留下来,日期也是按照从后往前生成的。然后调用数组的reverse反向join就正序了。

 

4.一个实例的6月份数据和另外一个实例的6月份数据有不同点么,或者重复使用6月份数据需要每次都计算么,答案显然不是。相同月份的数据多次使用要是只计算一次的话就可以大大提高效率,减少计算次数。

那么这就牵扯到数据持久化的问题,怎样把数据持久化呢或者暂时持久化?答案是把数据保存在类的属性上随用随拿。

 

var key = '_date_:' + Y + ':' + M;
indicotar.cache[key] || (indicotar.cache[key] = that.getDateString(Y, M));

按照年月生成一个key,如果没有数据就调用方法生成数据存入对应key的value。以后只用只用取出,合并字符串即可。

 

 

API

constructor:Cal(可以自行修改无依赖);
实例化:new Cal(document.body);
返回值:实例对象;
参数
Node *htmlNode nodeType为1的节点,控件会被append此节点内
Object O 配置控件可选参数
Number O.Y 设置的年份,默认当年,范围(1970-当年+10)
Number O.M 设置的月份,默认当月,范围(1-12)
String O.hasTitle 是否有日期控制栏,默认有'true'
String O.hasFoot 是否有脚注用来显示年月,默认无'false'
String O.style 日期分隔符,默认'-'
Number O.startYear 开始年,默认2006
Number O.endtYear 结束年,默认当年加10
Function O.ongetdate 用户点击日期单元格时触发,this指向实例,第一个参数为日期对应数组
Function O.onrender 控件插入值dom树时触发,this指向实例,第一个参数为控件对应的dom节点
Function O.ongetdatestring 获得月份所对应的日期字符串时触发,this指向实例,第一个参数为字符串
Function O.oncalframe 组成完毕控件node框架时触发,this指向实例,第一个参数为对应的dom节点
Function fn 类的回调函数,生成控件后触发

 

实例方法
方法名 参数 返回值
createDay Y:number/string(2012),M:number/string(0-11) 实例(1储存日期字符串至Cal的cache中,是数据持久化;2调用render)
render node:(this.elems),key:string('_date_:2012:0'),Y:number(2012),M:number(0-11) 实例(渲染控件至dom树)
getDateString Y:number(2012),M:number(0-11) htmlString
toString   string '2012-12-12' (获取选中日期对应的字符串)
valueOf   Array [2012,12,12] (获取选中日期对应的数组)
hide   实例 (隐藏控件)
show   实例 (显示控件)
setCss Object({'font-size':'12px','width':'300px'}) 实例 (为控件添加样式)
posted @ 2012-07-03 14:07  小玉西瓜  阅读(2931)  评论(5编辑  收藏  举报