vue自定义日期选择,类似美团日期选择,日历控件,vue日历区间选择

一个日历的控件,基于vue的,可以日历区间选择,可用于酒店日历区间筛选,动手能力强,可以修改成小程序版本的,先上效果图

 

里面的颜色样式都是可以修改的

 

选择范围效果

 

话不多说,直接上干货,代码可以直接复制访问

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no" />
  6     <meta name="renderer" content="webkit">
  7     <title></title>
  8 </head>
  9 <style>
 10 html,body{padding:0;margin:0;height:100%;}
 11 .header{
 12    width:100%;
 13    height:40px;
 14    text-align: center;
 15    position: relative;
 16    line-height: 40px;
 17 }
 18 .body{
 19    width: 100%;
 20    height:87%;
 21    height: -moz-calc(100% - 80px);
 22    height: -webkit-calc(100% - 80px);
 23    height: calc(100% - 80px);
 24    overflow-y: auto;
 25    position:absolute;
 26 }
 27 .golbal-left{
 28    width: 13px;
 29    height: 13px;
 30    border-top: 2px solid gainsboro;
 31    border-right: 2px solid gainsboro;
 32    transform: rotate(225deg);
 33    -webkit-transform: rotate(225deg);
 34    position: absolute;
 35    left: 16px;
 36    top: 15px;
 37 }
 38 .calendar {
 39   width: 100vw;
 40   text-align: center;
 41 }
 42 .week-title {
 43   overflow: hidden;
 44   position: fixed;
 45   margin-bottom: 1.5rem;
 46   background-color: #f6f6f8;
 47   z-index: 2;
 48 }
 49 .week-title>div {
 50   width: 14.28vw;
 51   height: 2rem;
 52   line-height: 2rem;
 53   float: left;
 54 }
 55 .box {
 56   position: absolute;
 57   top: 2rem;
 58   z-index: 1;
 59 }
 60 .data-title {
 61   height: 2rem;
 62   line-height: 2rem;
 63   border-top: 1px solid #ededed;
 64   border-bottom: 1px solid #ededed;
 65   clear: both;
 66 }
 67 .calendar-data {
 68   width: 100vw;
 69   clear: both;
 70 }
 71 .day {
 72   width: 14.28vw;
 73   height: 3rem;
 74   line-height: 1.6rem;
 75   float: left;
 76   display: flex;
 77   flex-direction: column;
 78 }
 79 .day.disabled{
 80   color:#ddd;
 81 }
 82 .active-start {
 83   color: white;
 84   background-color: #30b6af;
 85 }
 86 .active-start::after {
 87   content: '入住';
 88   font-size: .5rem;
 89 }
 90 .active {
 91   color: white;
 92   background-color: rgba(63,182,175,.5);
 93 }
 94 .active-end {
 95   color: white;
 96   background-color: #30b6af;
 97   position: relative;
 98 }
 99 .active-end::after {
100   content: '离开';
101   font-size: .5rem;
102 }
103 .active-end i{
104     position: absolute;
105     top:-120%;
106     width:100%;
107     height:100%;
108     background:rgba(0,0,0,1);
109     opacity:0.6;
110     border-radius:8px;
111     display: flex;
112     align-items: center;
113     justify-content: center;
114     font-style: normal;
115     font-size: 15px;
116     color:#fff;
117 }
118 .active-end i::after{
119     position: absolute;
120     content: '';
121     float: left;
122     width: 0; 
123     height: 0;
124     border-width: 10px;
125     border-style: solid;
126     border-color:#000 transparent transparent transparent;
127     opacity:1;
128     bottom:-20px;
129     left:50%;
130     margin-left:-10px;
131 }
132 .screenbottom{
133    height:35px;
134    width:100%;
135    display: flex;
136 }
137 .reset{
138    width:50%;
139    height:40px;
140    line-height: 40px;
141    color:#3E3E3E;
142    text-align: center;
143    background: #fff;
144 }
145 .determine{
146    width:50%;
147    height:40px;
148    line-height: 40px;
149    background: #48D8BF;
150    color:#fff;
151    text-align: center;
152 }
153 footer{
154     position: fixed;
155     bottom:0;
156     width:100%;
157 }
158 [v-cloak] 
159 {
160     display: none;
161 }
162 </style>
163 <body>
164     <div id='app' v-cloak>
165         <header class="header">
166           <span>时间范围</span>
167         </header>
168         <div class="body">
169             <div class='calendar'>
170                 <div class='week-title'>
171                     <div></div>
172                     <div></div>
173                     <div></div>
174                     <div></div>
175                     <div></div>
176                     <div></div>
177                     <div></div>
178                 </div>
179                 <div class='box'>
180                     <div class='calendar-body'>
181                         <div v-for="(item,index) in calendar">
182                             <!-- 标题 -->
183                             <div class='data-title'>
184                                 {{item.fullYear + '年' + item.fullMonth+'月'}}
185                             </div>
186                             <!-- 日期 -->
187                             <div class='calendar-data'>
188                                 <div class="day"                      
189                                 :class="item2.disabled + ' '+ item2.disabled2 + ' ' +item2.start_date + ' ' + item2.end_date +' ' + item2.active_date"  
190                                 v-for="(item2,index) in item.days" 
191                                 @click="selectDate(item2)">
192                                     {{item2.day}}
193                                 </div>
194                             </div>
195                         </div>
196                     </div>
197                 </div>
198             </div>
199         </div>
200         <footer>
201             <div class="screenbottom">
202                 <div class="reset">取消</div>
203                 <div class="determine">确定</div>
204             </div>
205         </footer>        
206     </div>
207 </body>
208 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
209  <script type="text/javascript">
210     let vm = new Vue({
211          el:'#app',
212          data:{
213             start:'',              //开始时间。从当天开始。
214             calendar:[],
215             month_length: 6,       //最长预定多少个月后的房间  读取总店配置。
216             max_reserve_days: 0,   //最长预定天数。,一个月按30天计划
217             max_reserve_date: '',  //最长可预定的日期。例如:2019-09-12
218             select_start_ymd : '', //入住开始提交时间  例如:2019-5-8
219             select_start_show: '', //入住开始显示时间  例如:05月08日
220             select_end_ymd: '',    //离店开始提交时间  例如:2019-5-8
221             select_end_show: '',   //离店开始显示时间  例如:05月08日
222             select_index:'start',  //记录当前点击时间,所对应的时间是开始时间还是结束时间
223             select_all_day:''
224          },
225          methods:{
226            initDate:function(){
227                 var _this = this;
228                 // 创建时间对象
229                 let date = new Date();
230                 //如果当前时间为凌晨6点前。则当前日期往前一天
231                 if (date.getHours() < 6) {
232                     date = new Date(date.getTime() - 86400 * 1000);
233                 }
234                 // 获取完整年月
235                 let fullDate = [
236                     date.getFullYear(),
237                     date.getMonth() + 1,
238                     date.getDate(),
239                     date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate()
240                 ];
241                 /**
242                  * 从缓存拿已经设置的开始和结束日期
243                  * 如果第一次用户是第一次进入。则设置默认值为,并且保存进缓存。
244                  */
245                 var select_start_ymd = '';
246                 var select_start_ymd_show = '';
247                 var select_end_ymd = '';
248                 var select_end_ymd_show = '';
249 
250                 if (select_start_ymd == '' || select_start_ymd == undefined || select_start_ymd == 'undefined' || _this.compareDate(select_start_ymd, fullDate[3]) == 3) {
251                     select_start_ymd = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
252                     select_start_ymd_show = _this.parseMonth(date.getMonth() + 1) + '' + _this.parseDay(date.getDate()) + '';
253                 }
254 
255                 if (select_end_ymd == '' || select_end_ymd == undefined || select_end_ymd == 'undefined' || _this.compareDate(select_end_ymd, fullDate[3]) == 3) {
256                     let temp_date = new Date(date.getTime() + 86400 * 1000)
257                     select_end_ymd = temp_date.getFullYear() + '-' + (temp_date.getMonth() + 1) + '-' + temp_date.getDate();
258                     select_end_ymd_show = _this.parseMonth(temp_date.getMonth() + 1) + '' + _this.parseDay(temp_date.getDate()) + '';
259                 }
260                 //设置数据。并且保存缓存
261                 _this.select_start_ymd = select_start_ymd
262                 _this.select_end_ymd = select_end_ymd
263 
264                 //通过月份。计划最长可预定天数和日期  ,最后一天为离店时间。所以多加一天可选择
265                 let max_reserve_days = _this.month_length * 30 + 1;
266 
267                 //最大天数转换成毫秒数。再转换成时间
268                 let max_date = new Date(date.getTime() + max_reserve_days * 24 * 60 * 60 * 1000);
269                 let max_reserve_date = max_date.getFullYear() + '-' + (max_date.getMonth() + 1) + '-' + max_date.getDate() + '';
270                 _this.max_reserve_days = max_reserve_days
271                 _this.max_reserve_date = max_reserve_date
272 
273                 //获取当前月份完整日期天数
274                 let cur_month_date = new Date(fullDate[0] + '-' + _this.parseMonth(fullDate[1]) + '-01')
275                 let cur_month = {};
276                 cur_month.fullYear = fullDate[0]; //
277                 cur_month.fullMonth = fullDate[1];  //
278                 cur_month.dayLength = _this.getMonthDays(cur_month.fullMonth, cur_month.fullYear);//当前月份总共有多少天
279                 cur_month.firstDayWeek = cur_month_date.getDay();  //当前月份第一天星期几0~7
280                 cur_month.curDay = date.getDate(); //当前天
281                 cur_month.days = [];
282                 //初始化天数
283                 var item = {};
284                 for (let i = 1; i <= cur_month.dayLength; i++) {
285                     item = {
286                         ymd: cur_month.fullYear + '-' + cur_month.fullMonth + '-' + i,
287                         ymd_cn: _this.parseMonth(cur_month.fullMonth) + '' + _this.parseDay(i) + '',
288                         day: i,
289                         disabled: i < cur_month.curDay ? 'disabled' : '',
290                     };
291                     //开始时间
292                     item.start_date = _this.compareDate(_this.select_start_ymd, item.ymd) == 2 ? 'active-start' : '';
293                     //中间的日期
294                     item.active_date = (_this.compareDate(_this.select_start_ymd, item.ymd) == 3 && _this.compareDate(_this.select_end_ymd, item.ymd) == 1) ? 'active' : '';
295                     //结束时间
296                     item.end_date = _this.compareDate(_this.select_end_ymd, item.ymd) == 2 ? 'active-end' : '';
297                     //超过设置最长日期。禁止选择
298                     item.disabled2 = _this.compareDate(max_reserve_date, item.ymd) == 3 ? 'disabled' : '';
299                     cur_month['days'].push(item);
300                 }
301 
302                 //前补0
303                 if (cur_month.firstDayWeek > 0) {
304                     for (let i = 0; i < cur_month.firstDayWeek; i++) {
305                         cur_month['days'].unshift('');
306                     }
307                 }
308 
309                 _this.calendar.push(cur_month)
310 
311                 var next_month_date;
312                 var nextfullDate = [];
313                 for (let i2 = 0; i2 < _this.month_length; i2++) {
314                     //下一个朋的天数信息
315                     next_month_date = new Date(fullDate[0], fullDate[1] + i2, '1');
316                     nextfullDate = [
317                         next_month_date.getFullYear(),
318                         next_month_date.getMonth() + 1,
319                     ]
320                     var next_month = {};
321                     next_month.fullYear = nextfullDate[0]; //
322                     next_month.fullMonth = nextfullDate[1];  //
323                     next_month.dayLength = _this.getMonthDays(next_month.fullMonth, next_month.fullYear);//当前月份总共有多少天
324                     next_month.firstDayWeek = next_month_date.getDay();  //当前月份第一天星期几0~6
325                     next_month.days = [];
326                      //初始化天数
327                     for (let i = 1; i <= next_month.dayLength; i++) {
328                         item = {
329                             ymd: next_month.fullYear + '-' + next_month.fullMonth + '-' + i,
330                             ymd_cn: _this.parseMonth(next_month.fullMonth) + '' + _this.parseDay(i) + '',
331                             day: i,
332                             active: '',
333                             disabled: '',
334                         };
335                         //开始时间
336                         item.start_date = _this.compareDate(_this.select_start_ymd, item.ymd) == 2 ? 'active-start' : '';
337                         //中间的日期
338                         item.active_date = (_this.compareDate(_this.select_start_ymd, item.ymd) == 3 && _this.compareDate(_this.select_end_ymd, item.ymd) == 1) ? 'active' : '';
339                         //结束时间
340                         item.end_date = _this.compareDate(_this.select_end_ymd, item.ymd) == 2 ? 'active-end' : '';
341                         //超过设置最长日期。禁止选择
342                         item.disabled2 = _this.compareDate(max_reserve_date, item.ymd) == 3 ? 'disabled' : '';
343                         next_month['days'].push(item);
344                     }
345                     //前补0
346                     if (next_month.firstDayWeek > 0) {
347                         for (let i = 0; i < next_month.firstDayWeek; i++) {
348                         next_month['days'].unshift('');
349                         }
350                     }
351                     _this.calendar.push(next_month)
352                 }
353                 console.log(_this.calendar);
354             },
355                         //格式月份期
356             parseMonth: function(month){
357                 month = parseInt(month);
358                 if(month <10){
359                     month = '0'+month
360                 }
361                 return month;
362             },
363 
364             //格式天
365             parseDay: function (day) {
366                 day = parseInt(day);
367                 if (day < 10) {
368                 day = '0' + day
369                 }
370                 return day;
371             },
372             // 获取每个月的天数
373             getMonthDays(m, year) {
374                 let days = [0, 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
375                 if (m != 2) {
376                     return days[m];
377                 }
378                 if ((year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0 && year % 100 === 0)) {
379                     return 29
380                 } else {
381                     return 28
382                 }
383             },
384             compareDate(date1, date2){
385                 var dateone = date1.replace(/-/g,'/');
386                 var datetwo = date2.replace(/-/g,'/');
387                 var oDate1 = new Date(dateone)
388                 var oDate2 = new Date(datetwo)
389                 if(oDate1.getTime() > oDate2.getTime()){
390                     return 1; //大于
391                 } else if (oDate1.getTime() == oDate2.getTime()) {
392                     return 2; //等于
393                 }else{
394                     return 3; //小于
395                 }
396             },
397             //点击日期按钮
398             selectDate:function(item){
399                 var _this = this;
400                 let select_data = item;
401                 console.log(select_data)
402                 let select_start_ymd = _this.select_start_ymd;
403                 let select_end_ymd = _this.select_end_ymd;
404                 //如果是点击不能用的地址
405                 if (select_data.disabled != ''){
406                     return false;
407                 }
408                 if (_this.select_index == 'start') {
409                     select_start_ymd = select_data.ymd;
410                     //如果选择的日期。是当前日期。或者比当前开始日期还早的。就 要把当前日期变为开始日期
411                    
412                     _this.select_start_ymd = select_start_ymd;
413                     _this.select_start_ymd_show = select_data.ymd_cn;
414                     _this.select_end_ymd = '';
415                     _this.select_end_ymd_show = '';
416 
417                     //将索引改为结束时间
418 
419                     _this.select_index = 'end';
420 
421                 } else if (_this.select_index == 'end'){
422                     let v = _this.compareDate(select_start_ymd, select_data.ymd)
423                     //如果选择的时间大于开始时间。则有效。否则重置开始时间
424                     if(v == 3 ){
425                         _this.select_end_ymd = select_data.ymd;
426                         _this.select_end_ymd_show = select_data.ymd_cn;
427                         //将索引改为结束时间
428                         _this.select_index = 'start';
429                         //保存数据到缓存
430                         _this.saveDate();
431                     }else{
432                         _this.select_start_ymd = select_data.ymd;
433                         _this.select_start_ymd_show = select_data.ymd_cn;
434                         _this.select_end_ymd = '';
435                         _this.select_end_ymd_show = '';
436                         //将索引改为结束时间
437                         _this.select_index = 'end';
438                     }
439 
440                 }
441                 _this.resetCalendar();
442             },
443             //重新计算一下日历
444             resetCalendar:function(){
445                 let _this = this;
446                 let calendar = _this.calendar;
447                 if(calendar.length > 0 ){
448                     for (var i in calendar){
449                         if(calendar[i]['days'].length > 0 ){
450                             for (var i2 in calendar[i]['days']) {
451                                 if (calendar[i]['days'][i2] != ''){
452                                     //开始时间
453                                     calendar[i]['days'][i2]['start_date'] = _this.compareDate(_this.select_start_ymd, calendar[i]['days'][i2]['ymd']) == 2 ? 'active-start' : '';
454                                     //中间的日期
455                                     calendar[i]['days'][i2]['active_date'] = (_this.compareDate(_this.select_start_ymd, calendar[i]['days'][i2]['ymd']) == 3 && _this.compareDate(_this.select_end_ymd, calendar[i]['days'][i2]['ymd']) == 1) ? 'active' : '';
456                                     //结束时间
457                                     calendar[i]['days'][i2]['end_date'] = _this.compareDate(_this.select_end_ymd, calendar[i]['days'][i2]['ymd']) == 2 ? 'active-end' : '';
458                                 }
459                             }    
460                         }
461                     }
462                 }
463 
464                 _this.calendar = calendar;
465             },
466             //如果设置结束时间成功。保存一次当前时间。并且计算总天数。到缓存中
467             saveDate:function(){
468                 var _this = this;
469                 var date1 = new Date(this.select_start_ymd.replace(/-/g,'/'));
470                 var date2 = new Date(this.select_end_ymd.replace(/-/g,'/'));
471                 //计算天数
472                 var days = parseInt((date2.getTime() - date1.getTime()) / 1000 / 86400);
473                 //保存缓存
474                 _this.select_all_day = days;
475             }
476          },computed:{
477 
478          },mounted(){
479             var _this = this;
480             _this.$nextTick(function () {
481                 _this.initDate()
482             })
483          }
484     })
485  </script>
486 </html>

 

 

 里面的备注很清晰,需要存起来下个页面用可以在saveDate这个函数中存进去localStorage中。

案例除了vue不基于任何插件,可以自定义修改,自定义程度高

posted @ 2020-01-11 16:44  太禾  阅读(6940)  评论(2编辑  收藏  举报