又重复造了个轮子,重复造轮子当然要有优点要不就没有存在价值。使用简单,方便。只要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'}) | 实例 (为控件添加样式) |