看看需求javascript
组件默认一直呈显示状态html
经过某种方式选择年、月,选择了年月后,日期列表作相应切换前端
经过单击某个具体的日期进行日期选择java
组件初始化时,可配置可选日期的上下限。可选日期和不可选日期须要有样式上的区别git
提供设定日期的接口,指定具体日期,日历面板相应日期选中github
日期选择面板默认隐藏,会显示一个日期显示框和一个按钮,点击这两个部分,会浮出日历面板。再点击则隐藏。dom
点击选择具体日期后,面板隐藏,日期显示框中显示选取的日期函数
增长一个接口,用于当用户选择日期后的回调处理this
增长一个参数及相应接口方法,来决定这个日历组件是选择具体某天日期,仍是选择一个时间段spa
当设置为选择时间段时,须要在日历面板上点击两个日期来完成一次选择,两个日期中,较早的为起始时间,较晚的为结束时间,选择的时间段用特殊样式标示
增长参数及响应接口方法,容许设置时间段选择的最小或最大跨度,并提供当不知足跨度设置时的默认处理及回调函数接口
在弹出的日期段选择面板中增长确认和取消按钮
先完成一个组件的基本结构
(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:文笔仍是不行,文章写的好烂。。