资讯专栏INFORMATION COLUMN

带你轻松搞定时间选择控件原理

tigerZH / 2761人阅读

摘要:虽然大家都用过这个时间选择控件,但是却很少有人去研究其中原理。最近这边本人利用闲暇时间自己写了一个时间选择控件,借这个时间选择控件向各位同学们阐述这个时间选择控件的原理。

前言

  说到这个时间选择控件,网上有很多各式各样的,相信很多同学们也都有用过,所以大家对这个也不陌生。虽然大家都用过这个时间选择控件,但是却很少有人去研究其中原理。最近这边本人利用闲暇时间自己写了一个时间选择控件,借这个时间选择控件向各位同学们阐述这个时间选择控件的原理。我向大家演示肯定是比较简单,相对来说更容易理解一点。但是呢,考虑到实用性,我就把这个时间选择控件改进了一下,让其变成了一个移动端时间选择控件,希望同学们如果喜欢我这边文章的话,麻烦帮个点个赞哦!不胜感谢!

项目演示 本文项目地址

https://github.com/ruichengpi...

本文演示地址

https://ruichengping.github.i...

本文演示效果图

--------------------------------分割线----------------------------------

完整项目地址(移动端) github地址

https://github.com/ruichengpi...

演示地址

https://ruichengping.github.i...

理一下思路

  基于上面的效果演示图,我们第一件事就是理清思路。很多同学呢,一开始如果做这个东西可能一头雾水,都不知道从哪里开始入手。这里我就大家理一下。

  对这种插件的开发,我个人建议先不要急着考虑其封装之类的情况,我们就从最简单的开始入手。那什么是最简单的呢?那肯定就是html+css+js的模式最简单的。什么意思呢?我这里解释一下,现在就是单纯做一个效果,html控制骨架,css美化样式,js实现交互,不要考虑复用性。

  既然我们选择html+css+js先去实现效果,那么着手开始先把时间选择控件的html的dom结构写出来,然后用css去调整其中的样式。html和css的内容很简单,这里我就不把代码贴出来,同学们看完这篇文章可以去我的github项目下中Jcalendarlearn文件夹查看。下面我们说一下交互有哪些东西。

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:如果觉得本文写的不错,请记得点赞哦!)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/87225.html

相关文章

  • 2017-08-12 前端日报

    摘要:前端日报精选中的操作符译理解教程构建一个预渲染友好的应用示例译如何学习开发如何编写轻量级框架中文译后台运行实战手册分析器入门博客众成翻译一款简单到极致的数据流框架使用组件的四个技巧关键请求教程奇舞周刊第期前端路上的旅行如何只用完 2017-08-12 前端日报 精选 JSX中的spread操作符【译】理解Service WorkerVue.js教程: 构建一个预渲染SEO友好的应用示例...

    zhiwei 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<