开发过程中遇到一个令人发指的,一个element-ui无法满足的日历需求, 改造其日历插件的代价太大,于是索性自己手写一个,需求如下:

1. 根据开始、结束时间计算时间覆盖的月份,渲染有限的可选择日期 

2. 日期下显示每日库存,库存为0的日期不可选择,同时不可作为中间日期被包含选择

3. 根据传入的默认选择日期初始化选择状态,若没有传入默认选择日期,初始化选择开始与结束时间

3. 其余功能与正常日历插件相同

 

基本思路: 1. 根据传入日期列表的开始与结束时间计算一共有几个月份,根据月份生成数组,数组内存放每月的覆盖天数,

                   2. 遍历月份数组 ,计算当前月份的一号是周几,根据这个补全当月时间,设置每天的选择状态(0:未选择,1:连带选择,2:被点击选择)为0,并初始化每个覆盖天数的库存,补全的其余天数库存设为0

                   3. 将每月补全的数据放入新数组,作为渲染每月Tab页的数据源

      4. 设置全局的开始与结束日期的选择状态,点击日期,判断设置开始日期选择状态为false,则记录开始时间并将状态设置为true,若开始日期状态为true则记录结束日期并设置结束日期选择状态为true,若结束日期状态为true则关闭选择框,并为父组件的开始与结束时间重新赋值

      5. 每次开启选择框则设置开始与结束日期选择状态为false

插件使用:

<data-picker :datedata="planDateList" :initstartdate='initstartdate' :initenddate='initenddate' :startdate='saleDate[0]' :enddate='saleDate[1]' :planid='resSalePlanId'></data-picker>

 效果图  :

elementui 节假日 elementui日历插件_数组

 

插件代码如下:

1  Vue.component('data-picker', {
  2         props: [
  3             'datedata',
  4             'startdate',
  5             'enddate',
  6             'planid',
  7             'initstartdate',
  8             'initenddate'
  9         ],
 10         data: function () {
 11             return {
 12                 currentDay: 1,
 13                 currentMonth: 1,
 14                 premonthDays: 0,
 15                 currentYear: 2002,
 16                 currentWeek: 1,
 17                 days: [],
 18                 daysTemplate: [01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],
 19                 monthCountArr: [31,29,31,30,31,30,31,31,30,31,30,31],
 20                 index: 0,
 21                 startWeekNum: 1,
 22                 monthArr: [],
 23                 monthDataArr:[],//整月数据
 24                 startDate: '',
 25                 startDateFlag: false,
 26                 startIndex: 0,
 27                 endDate: '',
 28                 endDateFlag: false,
 29                 endIndex: 0,
 30                 selStartMonthIndex: 0,
 31                 selEndMonthIndex: 0,
 32                 show: false,
 33                 errorFlag: true,//选择库存错误标志
 34                 allMonthData:[],//存放所有月份处理过后的数据
 35                 allMonthData:[],//存放所有月份处理过后的数据
 36                 
 37             }
 38         },
 39         mounted: function() {  //在vue初始化时调用
 40             this.initData();
 41         },
 42         component:{},
 43         methods: {
 44             initData: function(){
 45                 this.monthArr = []
 46 
 47                 this.startDate = this.startdate;
 48                 this.endDate = this.enddate;
 49                 //计算出有几个月  [{11:'11',days:['2-18-10-22']},{}]
 50                 var dateArr = this.datedata,
 51                     obj = {},
 52                     count = 0;
 53                 //按月份分组放数据 
 54                 for(var i=0; i<dateArr.length;i++){
 55                     var month = dateArr[i].startDate.split("-")[1];
 56                     if(!obj[month]){
 57                         count++;
 58                         obj[month] = month;
 59                         var dateObj = {};
 60                         //dateObj.leftAmount = dateArr[i].leftAmount;
 61                         dateObj.days = [];
 62                         dateObj.days.push({date:dateArr[i].startDate, leftAmount:dateArr[i].leftAmount, hasAmount: true});
 63                         dateObj[month] = month;
 64                         this.monthArr.push(dateObj);
 65                     }else{
 66                         this.monthArr[count-1].days.push({date:dateArr[i].startDate, leftAmount:dateArr[i].leftAmount, hasAmount: true})
 67                     }
 68                 }
 69                 //console.log(this.monthArr);
 70 
 71                 //初始化所有月数据
 72                 for(var m=0; m<this.monthArr.length;m++){
 73                     this.getCurMonthData(m);
 74                 }
 75 
 76                 //this.getCurMonthData(this.index);
 77 
 78                 //初始化选择
 79                 var start='',end='';
 80                 this.startDateFlag = false;
 81                 this.endDateFlag = false;
 82                 if(this.initstartdate && this.initenddate ){//有初始值
 83                     start = this.initstartdate;
 84                     end = this.initenddate;
 85                 }else{
 86                     start = this.startDate;
 87                     end = this.endDate;
 88                 }
 89                 for(var j=0; j<this.allMonthData.length; j++){
 90                     for(var k=0; k<this.allMonthData[j].length; k++){
 91 
 92                         if(this.allMonthData[j][k].date == start){
 93                             this.index = j;
 94                             this.monthDataArr = this.allMonthData[j];
 95                             this.selectDay(k, this.allMonthData[j][k]);
 96                         }
 97                         if(this.allMonthData[j][k].date == end){
 98                             this.index = j;
 99                             this.monthDataArr = this.allMonthData[j];
100                             this.selectDay(k, this.allMonthData[j][k]);
101                             break;
102                         }
103                     }
104                     
105                 }
106 
107                  //初始化第一页
108                  this.index = 0;
109                  this.currentMonth = this.monthArr[0].days[0].date.split("-")[1];
110                  this.currentYear = this.monthArr[0].days[0].date.split("-")[0];
111                  this.monthDataArr = this.allMonthData[0];
112                  this.show = false;
113             },
114             pickPre: function(currentYear,currentMonth,index){
115                 if(this.index >0){
116                     this.index--;
117                     if(!this.allMonthData[this.index]){//allMonthData
118                         //更新数据
119                         this.getCurMonthData(this.index);
120                     }else{
121                         this.currentMonth = this.monthArr[this.index].days[0].date.split("-")[1];
122                         this.currentYear = this.monthArr[this.index].days[0].date.split("-")[0];
123                         this.monthDataArr = this.allMonthData[this.index];
124                         //重置其他月份的选择状态
125                         //this.clearSelect(this.index);
126                     }
127                 }else{
128                     return;
129                 }
130             },
131             pickNext: function(currentYear,currentMonth,index){
132                 if(this.index < this.monthArr.length-1){
133                     this.index++;
134                     if(!this.allMonthData[this.index]){//allMonthData
135                         //更新数据
136                         this.getCurMonthData(this.index);
137                     }else{
138                         this.currentMonth = this.monthArr[this.index].days[0].date.split("-")[1];
139                         this.currentYear = this.monthArr[this.index].days[0].date.split("-")[0];
140                         this.monthDataArr = this.allMonthData[this.index];
141                         //重置其他月份的选择状态
142                         //this.clearSelect(this.index);
143                     }
144                 }else{
145                     return;
146                 }
147             },
148             //重置其他月份的选择状态
149             clearSelect: function(curIndex){
150                 for(var i=0; i<this.allMonthData.length; i++){
151                     if(i !== curIndex){
152                         for(var j=0; j<this.allMonthData[i].length; j++){
153                             this.allMonthData[i][j].selectStatus = 0;
154                         }
155                     }
156                 }
157             },
158             //根据当前选择月份整理数据 index
159             getCurMonthData: function(index){
160                 this.currentMonth = this.monthArr[index].days[0].date.split("-")[1];
161                 this.currentYear = this.monthArr[index].days[0].date.split("-")[0];
162 
163                 //判断是否是闰年
164                 if(this.isLeapYear(this.currentYear)){
165                     this.monthCountArr = [31,28,31,30,31,30,31,31,30,31,30,31];
166                 }else{
167                     this.monthCountArr = [31,29,31,30,31,30,31,31,30,31,30,31];
168                 }
169 
170                 //计算当前月的第一天是周几 dateArr[0].startDate
171                 this.startWeekNum = this.getStartWeekNum(this.monthArr[index].days[0].date);
172                 
173                 //初始化当前默认月的天数
174                 var monthDays = this.monthCountArr[parseInt(this.currentMonth)-1];
175                 this.days = this.daysTemplate.slice(0,monthDays);
176                 //获取前一个月有多少天
177                 this.premonthDays=0;
178                 if(this.currentMonth == 1){
179                     this.premonthDays = 31;
180                 }else{
181                     this.premonthDays = this.monthCountArr[parseInt(this.currentMonth)-2];
182                 }
183 
184                 //处理整月数据并格式化当前月的日期 31 -- 2018-10-31
185                 for(var n=0;n<this.days.length; n++){
186                     this.days[n] = this.currentYear + '-' + this.currentMonth + '-' + (this.days[n] > 9 ? this.days[n] : '0'+ this.days[n]);
187                 }
188                 //初始化当前框的日期数组 比如: 一号在周四 则数组前加入 28,29,30,31 或 27,28,29,30 或,26,27,28,29 或25,26,27,28
189                 for(var k=parseInt(this.startWeekNum); k>0; k--){
190                     this.days.unshift( (this.currentMonth == 1 ? this.currentYear-1 : this.currentYear) + '-' + (this.currentMonth == 1 ? 12 : this.currentMonth-1) + '-' + (this.daysTemplate[this.premonthDays-k] > 9 ? this.daysTemplate[this.premonthDays-k] : '0'+this.daysTemplate[this.premonthDays-k]) )
191                 }
192                 //console.log(this.days);
193                 //处理形成整月数据
194                 this.handelTheMonthData(this.days,this.monthArr,index);
195             },
196             //处理形成整月数据 monthDataArr
197             handelTheMonthData: function(days,monthArr,index){
198                 
199                     this.monthDataArr = [];
200                     var curMonthData = this.monthArr[index].days;
201                     for(var n=0;n<days.length; n++){
202                         var obj={},flag = false,leftAmount=0;
203                         for(var m=0; m<curMonthData.length; m++){
204                             if(new Date(curMonthData[m].date).getTime() == new Date(days[n]).getTime() ){//当前日期存在库存
205                                 flag = true;
206                                 leftAmount = curMonthData[m].leftAmount;
207                             }
208                         }
209                         if(flag){
210                             obj.date = days[n];
211                             obj.leftAmount = leftAmount;
212                             obj.selectStatus = 0; //0:未选择 1:连带选择 2:被选中
213                             this.monthDataArr.push(obj);
214                         }else{
215                             obj.date = days[n];
216                             obj.leftAmount = 0;
217                             obj.selectStatus = 0; //0:未选择 1:连带选择 2:被选中
218                             this.monthDataArr.push(obj);
219                         }
220                     }
221                     this.allMonthData[index] = this.monthDataArr;
222                     //console.log(this.allMonthData);
223                     return this.monthDataArr;
224                
225             },
226             //计算当前月的第一天是周几
227             getStartWeekNum: function(date){
228                 var date = new Date(date);
229                 date.setDate(1);
230                 //console.log(date.getDay())
231                 return date.getDay();
232             },
233             //判断是否是闰年
234             isLeapYear: function(year){
235                 if((year%4==0 && year%100!=0) || year%400==0){
236                     return true;
237                 }else{
238                     return false;
239                 }
240             },
241             pickUp: function(){
242                 this.show = !this.show;
243                 this.startDateFlag = false;
244                 this.endDateFlag = false;
245             },
246             selectDay: function(index,dayobject){//this.startDate  this.endDate
247                 //判断当前是否可点击
248                 if(dayobject.leftAmount == 0){
249                     return;
250                 }
251                 //console.log(dayobject);
252 
253                 self.errorFlag = true;
254                 //初始化各日期selectStatus值
255                 for(var i=0; i<this.monthDataArr.length; i++){
256                     this.monthDataArr[i].selectStatus = 0;
257                 }
258 
259                 if(this.startDateFlag){
260                     this.endDate = dayobject.date;
261                     this.endDateFlag = true;
262                     this.endIndex = index;
263                     this.selEndMonthIndex = this.index;
264                 }else{
265                     this.startDate = dayobject.date;
266                     this.startDateFlag = true;
267                     this.startIndex = index;
268                     this.selStartMonthIndex = this.index;
269                     //重置其他月份的选择状态
270                     this.clearSelect(this.index);
271                 }
272                 //设置selectStatus值  :class="{{"select":(dayobject.selectStatus == 2),"subSelect":(dayobject.selectStatus == 1) }}" 
273                 this.monthDataArr[index].selectStatus = 2;
274 
275                 if(this.endDateFlag){//判断是否可连续选择 计算连续时间 若可连续设置selectStatus值 关闭弹窗 
276                     //判断大小是否颠倒
277                     if(this.selStartMonthIndex > this.selEndMonthIndex || (this.selStartMonthIndex==this.selEndMonthIndex && this.startIndex>this.endIndex) ){
278                         var box,dateBox,indexBox;
279                         box = this.selStartMonthIndex;
280                         this.selStartMonthIndex = this.selEndMonthIndex;
281                         this.selEndMonthIndex = box;
282 
283                         indexBox = this.startIndex;
284                         this.startIndex = this.endIndex;
285                         this.endIndex = indexBox;
286 
287                         dateBox = this.startDate;
288                         this.startDate = this.endDate;
289                         this.endDate = dateBox;
290                     }
291 
292                     //判断是否跨月
293                     var startMonth = this.startDate.split("-")[1];
294                     if(this.selEndMonthIndex !== this.selStartMonthIndex){//不同月 startMonth !== this.currentMont
295                         //获取开始月的index 开始月到月尾 开始月到结束月的中间月的全部 以及结束月到点击时间 selectStatus变为1
296                         for(var i=this.selStartMonthIndex; i<this.selEndMonthIndex+1; i++){
297                             for(var j=0; j<this.allMonthData[i].length; j++){
298 
299                                 // if(this.allMonthData[i][j].leftAmount == 0){//
300                                 //     self.errorFlag = false;
301                                 //     return;
302                                 // }
303                                 
304                                 if(i==this.selStartMonthIndex && j == this.startIndex && this.allMonthData[i][j].leftAmount !==0){//开始月点击的第一天
305                                     this.allMonthData[i][j].selectStatus = 2;
306                                 }else if(i==this.selStartMonthIndex && j > this.startIndex && this.allMonthData[i][j].leftAmount !==0){//开始月其它天
307                                     this.allMonthData[i][j].selectStatus = 1;
308                                 }else if(i==this.selEndMonthIndex && j == this.endIndex && this.allMonthData[i][j].leftAmount !==0){//结束月电机的最后一天
309                                     this.allMonthData[i][j].selectStatus = 2;
310                                 }else if(i==this.selEndMonthIndex && j < this.endIndex && this.allMonthData[i][j].leftAmount !==0){
311                                     this.allMonthData[i][j].selectStatus = 1;
312                                 }else if(i<this.selEndMonthIndex && i>this.selStartMonthIndex && this.allMonthData[i][j].leftAmount !==0){//中间月
313                                     this.allMonthData[i][j].selectStatus = 1;
314                                 }
315                             }
316                         }
317                     }else{//同一月
318                         for(var i=this.startIndex; i<this.endIndex+1; i++){
319                             if(this.monthDataArr[i].leftAmount !== 0){
320                                 if(i == this.startIndex || i == this.endIndex){
321                                     this.monthDataArr[i].selectStatus = 2;
322                                 }
323                                 // if(i == this.endIndex){
324                                 //     this.monthDataArr[i].selectStatus = 2;
325                                 // }
326                                 else {
327                                     this.monthDataArr[i].selectStatus = 1;
328                                 }
329                             }else{
330                                 self.errorFlag = false;
331                                 return;
332                             }
333                             
334                         }
335                     }
336                     //设置值
337                     this.$parent.$parent.$parent.$parent.curEditData.saleDate=[];
338                     this.$parent.$parent.$parent.$parent.curEditData.saleDate.push(this.startDate);
339                     this.$parent.$parent.$parent.$parent.curEditData.saleDate.push(this.endDate);
340 
341                     //console.log('111111111~~~');
342                     //console.log(this.allMonthData)
343                     
344                     this.pickUp();
345                 }
346                 
347             }
348         },
349         watch: {
350             'planid': function(){
351                 this.clearSelect(-1);
352                 this.allMonthData = [];
353                 this.initData(true);
354             }
355         },
356         template: 
357             '<div class="calendarBox">'+
358                 '<div id="calendarDate" class="calendarInput" @click="pickUp()">'+
359                     '<span>{{startDate}}</span> <span> ~ </span> <span>{{endDate}} <i slot="suffix" class="el-input__icon el-icon-date"></i></span>'+
360                 '</div> '+
361                 '<div class="calendar" v-show="show">'+
362                     '<div class="month">'+
363                         '<ul class="clearfix">'+
364                             '<li v-if="index >= 1" class="arrow" @click="pickPre(currentYear,currentMonth,index)"> ❮ </li>'+
365                             '<li v-if="index < 1" class="disabledArrow" @click="pickPre(currentYear,currentMonth,index)"> ❮ </li>'+
366                             '<li class="year-month" @click="pickYear(currentYear,currentMonth)">'+
367                                 '<span class="choose-year">{{ currentYear }} 年 </span>'+
368                                 '<span class="choose-month">{{ currentMonth }} 月</span>'+
369                             '</li>'+
370                             '<li v-if="index < monthArr.length-1" class="arrow" style="text-align:right;" @click="pickNext(currentYear,currentMonth,index)"> ❯ </li>'+
371                             '<li v-if="index >= monthArr.length-1" class="disabledArrow" style="text-align:right;" @click="pickNext(currentYear,currentMonth,index)"> ❯ </li>'+
372                        '</ul>'+
373                     '</div>'+
374                     '<ul class="weekdays clearfix">'+
375                         '<li>日</li>'+
376                         '<li>一</li>'+
377                         '<li>二</li>'+
378                         '<li>三</li>'+
379                         '<li>四</li>'+
380                         '<li>五</li>'+
381                         '<li>六</li>'+  
382                         '<p v-show="!errorFlag">不可选择库存为0的连续时间段</p>'+
383                     '</ul>'+
384                     '<ul class="days clearfix">'+  
385                         '<li v-for="(dayobject,index) in monthDataArr" @click="selectDay(index,dayobject)">'+
386                             '<template v-if="dayobject.selectStatus == 0">'+ 
387                                 '<span v-if="dayobject.leftAmount == 0" class="other-month">{{ new Date(dayobject.date).getDate() }}</span>'+
388                                 '<span v-else >'+
389                                     '<span v-if="new Date(dayobject.date).getFullYear() == new Date().getFullYear() && new Date(dayobject.date).getMonth() == new Date().getMonth() && new Date(dayobject.date).getDate() == new Date().getDate()" class="active">'+
390                                         '{{ new Date(dayobject.date).getDate() }}'+
391                                         '<span style="color:#409EFF">库存:{{ dayobject.leftAmount }}</span>'+
392                                     '</span>'+
393                                     '<span v-else>{{ new Date(dayobject.date).getDate() }}</br><span style="color:#409EFF">库存:{{ dayobject.leftAmount }}</span></span>'+
394                                 '</span>'+
395                             '</template>'+
396                             '<template v-if="dayobject.selectStatus == 1">'+ 
397                                 '<span v-if="dayobject.leftAmount == 0" class="other-month subSelect">{{ new Date(dayobject.date).getDate() }}</span>'+
398                                 '<span class="subSelect" v-else >'+
399                                     '<span v-if="new Date(dayobject.date).getFullYear() == new Date().getFullYear() && new Date(dayobject.date).getMonth() == new Date().getMonth() && new Date(dayobject.date).getDate() == new Date().getDate()" class="active">'+
400                                         '{{ new Date(dayobject.date).getDate() }}'+
401                                         '<span class="inventory">库存:{{ dayobject.leftAmount }}</span>'+
402                                     '</span>'+
403                                     '<span v-else>{{ new Date(dayobject.date).getDate() }}</br><span class="inventory">库存:{{ dayobject.leftAmount }}</span></span>'+
404                                 '</span>'+
405                             '</template>'+
406                             '<template v-if="dayobject.selectStatus == 2">'+ 
407                                 '<span v-if="dayobject.leftAmount == 0" class="other-month select">{{ new Date(dayobject.date).getDate() }}</span>'+
408                                 '<span class="select" v-else >'+
409                                     // '<span class="selectFlag" v-if="dayobject.selectStatus == 1">开始</span>'+
410                                     // '<span class="selectFlag" v-if="dayobject.selectStatus == 2">结束</span>'+
411                                     '<span v-if="new Date(dayobject.date).getFullYear() == new Date().getFullYear() && new Date(dayobject.date).getMonth() == new Date().getMonth() && new Date(dayobject.date).getDate() == new Date().getDate()" class="active">'+
412                                         '{{ new Date(dayobject.date).getDate() }}'+
413                                         '<span class="inventory">库存:{{ dayobject.leftAmount }}</span>'+
414                                     '</span>'+
415                                     '<span v-else>{{ new Date(dayobject.date).getDate() }}</br><span class="inventory">库存:{{ dayobject.leftAmount }}</span></span>'+
416                                 '</span>'+
417                             '</template>'+
418                         '</li>'+
419                     '</ul>'+
420                 '</div> '+
421             '</div> '
422     })