怎样实现一个datePicker(日期选择)组件

百度前端技术学院上有一个任务,要实现一个日期选择组件,本文由此而来~

  1. 看看需求
  • 组件默认一直呈显示状态
  • 通过某种方式选择年、月,选择了年月后,日期列表做相应切换
  • 通过单击某个具体的日期进行日期选择
  • 组件初始化时,可配置可选日期的上下限。可选日期和不可选日期需要有样式上的区别
  • 提供设定日期的接口,指定具体日期,日历面板相应日期选中
  • 日期选择面板默认隐藏,会显示一个日期显示框和一个按钮,点击这两个部分,会浮出日历面板。再点击则隐藏。
  • 点击选择具体日期后,面板隐藏,日期显示框中显示选取的日期
  • 增加一个接口,用于当用户选择日期后的回调处理
  • 增加一个参数及相应接口方法,来决定这个日历组件是选择具体某天日期,还是选择一个时间段
  • 当设置为选择时间段时,需要在日历面板上点击两个日期来完成一次选择,两个日期中,较早的为起始时间,较晚的为结束时间,选择的时间段用特殊样式标示
  • 增加参数及响应接口方法,允许设置时间段选择的最小或最大跨度,并提供当不满足跨度设置时的默认处理及回调函数接口
  • 在弹出的日期段选择面板中增加确认和取消按钮

先完成一个组件的基本结构

    (function(window,document){
       function Calendar(options){
          //传入配置的中的参数
          this.init();
       } 
       Calendar.prototype={
            init:function(){
               this.createDom();
               this.loadCss();
               this.cacheDom();
               this.bindEvents();
               this.render();
            },
            loadCss:function(){
               // 把组件所需的样式表动态加载进来
            },
            createDom:function(){
               // 创建dom对象或者创建html片段或者创建template
            },
            cacheDom:function(){
               // 存储dom 对象
            },
            bindEvents:function(){
               //事件绑定
            },
            render:function(){
              //渲染函数,更新数据或样式
            }
       }
       window.Calendar=Calendar;//把组件对象绑定到全局
    }(window,document));

通常我写组件时的基本结构如上,你可以根据组件的需要或者自己习惯进行编写。然后就可以在html里面添加以下的代码就可以调用我们的组件了,

<script src='calendar.js></script>
<script type='text/javascript'>
   var a=new Calendar({
      // 各种配置
      /* 类似于 id:'myCalendar'
         onSelected:function(){
                    alert('hello');
        }
     */
   });
</script>

下面再看一下我们的需求,我们来一 一分析

需求也不是很多嘛,手动斜眼~
先上图,根据图再慢慢分析

概要图
概要图

其实我们看了需求之后,每个人都会有一个大概的思路,下面说一下我的思路
首先,要实现一个日期选择器,最重要的就是要有一个日历,根据不同的年份和月份,日期面板上回显示每一天和对应的周几~
其实实现这一点的话就两点

  • 第一,要根据年份和月份算出每月有多少天
  • 第二,要计算出每月的第一天(1号)是周几
    伪代码如下:
 /**
     * @param  {string} year  年份
     * @param  {string} month 月份
     * @param  {string} day   号
     * @return {object}  message
     * message{
     * year   年份
     * month  月份
     * monthLen  那个月的天数
     * whichDay  1号是周几
     * day       号
     * }    
     */
     function calculate(year,month,day){
                var date=year+'/'+month+'/'+'1';
                var whichDay=new Date(date).getDay();
              var message={
                    year:year,
                    month:month,
                    monthLen:new Date(year,month,0).getDate(),
                    whichDay:whichDay,
                    day:day
              };
              return message;
     },

我想看完代码之后大家应该比较疑惑的是获取每个月天数的那句代码,这个比较优雅的做法是从这里看到的,
注意:在Date对象里month为0代表的是1月份,month为5代表6月份,所以我new Date(year,5,0)代表的六月份的第0天,即5月份的最后一天,所以还可以用getDate()获取5月份的长度,getDate方法是返回指定日期对象的月份中的第几天(1-31)。
所以当我们点击了月份加减/年份加减的按钮时,向calculate函数传入变化后的year,month参数,然后进行渲染,日历面板改变

其次,”选择时间段并且另处于开始时间和结束时间之间的日期添加特殊的样式“这一点也是花了不少时间来写,
伪代码如下:

// 初始化
var firstDate,secondDate=[0,0,0];
//点击日历面板上的日期的点击事件的执行函数的片段,每当点击事件被触发,就会执行该片段

if(self.isSelectRange){
             var date=[self.year.innerHTML,self.month.innerHTML,ele.innerHTML];            
             if(self.firstDate[0]===0){// 
                if(self.secondDate[0]===0){//两个日期都没有被设置
                     self.firstDate=date;
                }else{//firstDate没有被设置,secondDate已经被设置,
                     
                }
             }else{
                if(self.secondDate[0]===0){//firstDate已经设置,
                    self.secondDate=date;
                    if(compareDate(self.firstDate.join('/'),self.secondDate.join('/'))){//如果第一个选择的日期大于第二次选择的日期,进行交换
                        self.firstDate=[self.secondDate,self.secondDate=self.firstDate][0];
                    } 
                }else{//两个日期都已经被设置,已经选择了两个元素,再次选择则都
                   self.secondDate=[0,0,0];
                   self.firstDate=date;
                   self.clearDayInRangeStyle();
                }
             }
             self.day.innerHTML=ele.innerHTML;
             self.render();

firstDate,secondDate分别代表开始时间和结束时间。每次触发日期的点击事件时,就会执行以上的代码片段,对firstDate和secondDate进行更改,这样的话,无论是我对日历面板进行更新或者对开始时间和结束时间之间的日期显示不同的样式,都可以通过firstDate和secondDate来实现。

显示不同的样式就判断日期是否在开始时间和结束时间之间,每次重新render的时候就给选择过的firstDate和secondDate添加样式。

包括计算开始时间和结束时间之间的跨度是否在设定的跨度内,我们点击按钮后进行判断。
最后,看看render函数怎么实现
关于render函数,有以下几点需要注意:

  • 清除日历面板上的所有内容和样式,样式通过清除每个单元格上的类实现
  • 根据每月1号是周几和每月的长度生成每月的日历
  • 根据记录的fisrtDate和secondDate来显示已经选择过的选择的样式

以上大概是我的思路,我也实现了一个组件,有兴趣的朋友可以点这里,欢迎找bug~
ps:文笔还是不行,文章写的好烂。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,400评论 25 707
  • 内容抽屉菜单ListViewWebViewSwitchButton按钮点赞按钮进度条TabLayout图标下拉刷新...
    皇小弟阅读 46,702评论 22 664
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 手机上的一个抓娃娃小游戏原型,有设定抓住的几率,这里就不做判断了,只实现抓取的效果! HTML JS CSS
    fixppy阅读 741评论 0 2
  • 概览与综述 基本形式 解释: DOCTYPE 声明了文档类型 位于标签 描述了文档附加信息 位于标签 ...
    熊白白阅读 319评论 0 2