[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>' );<br>} |
大家可能要怀疑为什么先写的是 </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'}) | 实例 (为控件添加样式) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!