带你轻松搞定时间选择控件原理
2017-08-12 15:02
417 查看
前言
说到这个时间选择控件,网上有很多各式各样的,相信很多同学们也都有用过,所以大家对这个也不陌生。虽然大家都用过这个时间选择控件,但是却很少有人去研究其中原理。最近本人利用闲暇时间自己写了一个时间选择控件,借这个时间选择控件向各位同学们阐述这个时间选择控件的原理。我向大家演示肯定是比较简单,相对来说更容易理解一点。但是呢,考虑到实用性,我就把这个时间选择控件改进了一下,让其变成了一个移动端时间选择控件,希望同学们如果喜欢我这边文章的话,麻烦帮个点个赞哦!不胜感谢!项目演示
本文项目地址
https://github.com/ruichengping/Jcalendar/tree/master/learn本文演示地址
https://ruichengping.github.io/Jcalendar/learn/本文演示效果图
——————————–分割线———————————-
完整项目地址(移动端)
github地址
https://github.com/ruichengping/Jcalendar演示地址
https://ruichengping.github.io/Jcalendar/demo/理一下思路
基于上面的效果演示图,我们第一件事就是理清思路。很多同学呢,一开始如果做这个东西可能一头雾水,都不知道从哪里开始入手。这里我就大家理一下。对这种插件的开发,我个人建议先不要急着考虑其封装之类的情况,我们就从最简单的开始入手。那什么是最简单的呢?那肯定就是html+css+js的模式最简单的。什么意思呢?我这里解释一下,现在就是单纯做一个效果,html控制骨架,css美化样式,js实现交互,不要考虑复用性。
既然我们选择html+css+js先去实现效果,那么着手开始先把时间选择控件的html的dom结构写出来,然后用css去调整其中的样式。html和css的内容很简单,这里我就不把代码贴出来,同学们看完这篇文章可以去我的github项目下中Jcalendar下learn文件夹查看。下面我们说一下交互有哪些东西。
JS交互实现
关于这个JS交互,我们首先要弄清楚这个时间选择控件有哪些交互。我先列举一下:年份、月份的增加减少按钮
根据input框的位置,设置时间选择器的位置
根据年份、月份获取对应的日期数据
日期的选择
时间选择器显示隐藏
下面一一这些功能。
根据年份、月份获取对应的日期数据
我们先来阐述这个功能是如何实现,这是整个时间选择控件的基石,弄清楚这个,后面的问题都会变得简单。初看到这个确实很难,一头雾水,都不知道如何下手。遇到这种问题的时候,先不要考虑如何去实现,首先我们弄清楚这个日期数据是由那几块组成。我认真地想想,发现每一组日期数据都有这样一个等式。日期数据=上一月的日期+这个月的日期+下个月的日期
那为什么会这么组成呢?可能有同学们有这样子的疑问,不急不急,听我接下来解释一下。
一个星期是有七天,我们最长的一个月是31天,就是4个星期余三天。如果每一行代表星期,那么五行就可以搞定了。但是看效果演示图我们可以看出来,我们用了6行。为什么会多一行?这个问题很好解释,并不是每一个月的第一天都是从星期天开始的,所以我们要考虑最坏的情况。如果从星期六开始,此时需要6+31=37格(换上一下,就是5行多2格)。为了满足这种最坏的情况,我们就需要6行了。
通过上面解释,我们可以发现有一个特例并不满足这个等式。那就是这个月第一天是从星期天开始的。不过这个特例并不影响我们用这种思路去思考问题,所以我们可以不管这个特例。下面我就看一下,这每一块数据是如何得到的。
上个月
关于得出这块数据,我们先不要考虑其具体组成。首先考虑的是个数,需要几个我们给它弄几个。怎么知道需要多少个呢?很简单,弄清楚这个月的第一天是星期几就可以了。/** *获取currentYear年currentMonth月的第一天是星期几 *month参数是要比实际上少一天的 *0 代表星期天 6代表星期六 **/ new Date(currentYear,currentMonth-1,1).getDay();
当我得出需要几个上一月日期数据之后,我们还需要一样东西。那就是上一个月的最后一天,根据这个来往前推。
/** *获取currentYear年currentMonth月的最后一天的日期 *month参数是要比实际上少一天的 **/ new Date(currentYear,currentMonth-1,0).getDate();
这个月
这个月的日期数据相比较上一个就简单多了,只需要知道这一月的第一天和最后一天即可。//获取currentYear年currentMonth月的第一天的日期 new Date(currentYear,currentMonth-1,1).getDate(); //获取currentYear年currentMonth月的最后一天的日期 new Date(currentYear,currentMonth,0).getDate();
下一月
这块数据也非常简单,总共7*6=42格,剩下几格就往里面填几个。我们这里只需要知道下一个月的第一天是多少就行了。//获取currentYear年currentMonth月的下一月的一天的日期 new Date(currentYear,currentMonth,1).getDate();
最终的JS代码
//根据年,月获取日数组 function getMonthData(year, month, day) { var days = []; var today = new Date(); if (!year | !month | !day) { year = today.getFullYear(); month = today.getMonth() + 1; day = today.getDate(); } //获取该月第一天的Date对象 var firstDateObj = new Date(year, month - 1, 1); //获取该月第一天对应的星期几 var firstDateWeekDay = firstDateObj.getDay(); //获取该月最后一天的Date对象 var lastDateObj = new Date(year, month, 0); //获取该月最后一天的日期 var lastDate = lastDateObj.getDate(); //获取上一个月最后一天的Date对象 var lastDateOfPrevMonthObj = new Date(year, month - 1, 0); //获取上一个月最后一天的日期 var lastDateOfPrevMonth = lastDateOfPrevMonthObj.getDate(); //上月 for (var i = 0; i < firstDateWeekDay; i++) { var className = "available disabled"; var thisMonth = month - 1; var date = lastDateOfPrevMonth - firstDateWeekDay + i + 1; if (thisMonth === 0) { thisMonth = 1; } days.push({ "date": date, "showDate": date, "thisMonth": thisMonth, "className": className }); } //本月 for (var i = 0; i < lastDate; i++) { var className = "available"; var date = i + 1; var thisMonth = month; if (date === day) { className = "available current"; } if (today.getDate() === date && today.getFullYear() === year && today.getMonth() + 1 === month) { days.push({ "date": date, "showDate": "今天", "thisMonth": thisMonth, "className": className }); } else { days.push({ "date": date, "showDate": date, "thisMonth": thisMonth, "className": className }); } } var nextMonthLength = days.length; //下月 for (var i = 0; i < 7 * 6 - nextMonthLength; i++) { var className = 'available disabled'; var date = i + 1; var thisMonth = month + 1; if (thisMonth === 13) { thisMonth = 12; } days.push({ "date": date, "showDate": date, "thisMonth": thisMonth, "className": className }); } return { "year": firstDateObj.getFullYear(), "month": firstDateObj.getMonth() + 1, "days": days } }
年份、月份的增加减少按钮
这块没有难的点,需要注意的就是临界值得判断。比如说12月再加1个月,不能变成13月,而是年份加1,月份置为1.根据input框的位置,设置时间选择器的位置
这块内容也很简单,弄清楚left值和top值是如何计算的即可。top值=input输入框到浏览器窗口顶部的距离+input自身的高度
left值=input输入框到浏览器窗口左边的距离
上面需要注意的是距离游览器而不是整个文档,因为我们用的fixed而不是absolute。
日期的选择
这里没有难点,但是有一个新手非常容易犯错的错误。在为日期绑定事件的时候,新手很容易就会找到当前页面所有日期给它绑定事件。这样显然是行不通的,因为日期数据是不断变得,也就是日期这些dom元素是会替换了的,之前绑定的事件也就不见了,所以我建议大家用事件委托机制。可能会有人反驳我,每一天改变年份和月份的时候在重新绑定一次不就完了,当然这样也是可以的。但是不建议,简单的事情不要复杂化,无端增加开销。时间选择器显示隐藏
这个小功能点,很简单,没啥可讲。需要注意多个实例并且只有一个时间选择器的dom结构的情况下,你该如何设计你的显示隐藏。结语
到这里我们就把整个时间选择控件实现整个思路都理了一遍,相信同学们已经知道如何实现一个时间选择控件了。快去自己动手做一个自己专属的时间选择控件吧!(ps:如果觉得本文写的不错,请记得点赞哦!)相关文章推荐
- 轻松实现可扩展自定义的Android滚轮时间选择控件
- jquery 时间控件怎么能禁止输入只能选择日期?
- MxxCalendar 日期时间选择控件
- JS日期和时间选择控件升级版(自写)
- 带时间选择得JS日期控件
- 一个JS时间选择控件
- 猎豹MFC--DataTimePicker日期时间选择控件CDatatimeCtrl CTime CTimeSpan时间间隔
- 安卓开发-高仿ios时间选择控件
- weui 时间控件含全天 上午 下午 选择
- asp.net中的时间日期选择控件
- LCalendar v1.71移动端日期时间选择控件
- JS日历控件 (兼容IE firefox) 可选择时间
- ASP.net 页面添加时间选择控件
- bootstrap-datetimepicker:基于twitter bootstrap的日期/时间选择控件
- bootstrap-datetimepicker:基于twitter bootstrap的日期/时间选择控件
- AppiumLibrary 时间控件的选择
- 基于zepto的移动端日期和时间选择控件
- My97 datepicker 日期控件添加时间自动选择 年龄,生肖,星座
- JQuery制作简单选择时间控件
- Android之日期时间选择控件DatePicker和TimePicker