开发过程中遇到一个令人发指的,一个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>

效果图  :

插件代码如下:

  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 })

VUE自定义(有限)库存日历插件的更多相关文章

  1. vue自定义全局组件(自定义插件)

    有时候我们在做开发的时候,就想自己写一个插件然后就可以使用自己的插件,那种成就感很强.博主最近研究element-ui和axios的时候,发现他们是自定义组件,但是唯一有一点不同的是,在用elemen ...

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

    一个日历的控件,基于vue的,可以日历区间选择,可用于酒店日历区间筛选,动手能力强,可以修改成小程序版本的,先上效果图 里面的颜色样式都是可以修改的 选择范围效果 话不多说,直接上干货,代码可以直接复 ...

  3. vue从入门到进阶:自定义指令directive,插件的封装以及混合mixins(七)

    一.自定义指令directive 除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令.注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件.然而,有的 ...

  4. Vue自定义日历组件

    今天给大家介绍Vue的日历组件,可自定义样式.日历类型及支持扩展,可自定义事件回调.Props数据传输. 线上demo效果 示例 Template: <Calendar :sundayStart ...

  5. vue自定义插件封装,实现简易的elementUi的Message和MessageBox

    vue自定义插件封装示例 1.实现message插件封装(类似简易版的elementUi的message) message组件 <template>     <transition  ...

  6. 一款基于jQuery日历插件的开发过程

    这个插件的设置选项,所有样式都设置成自定义,提供回调函数,方便在外部进行扩展 css设置是可变的  也就是说  日历的样式是定制的: /******************************** ...

  7. 11个实用jQuery日历插件

    1. FullCalendar FullCalendar是很出名的jQuery日历插件,它支持拖拽等功能,整合了Google Calendar,而且可以通过JSON来绑定事件,设计师可以轻松地自定义日 ...

  8. XgCalendar日历插件动态添加参数

    在使用xgcalendar日历插件的时候,参数数组并非只有类型.显示时间.时区等这些参数,还可以根据extParam自定义参数扩展搜索条件,例如根据用户Id搜索不同用户的日历信息,需要将用户的Id存在 ...

  9. JQuery日历插件My97DatePicker日期范围限制

    My97DatePicker是一个非常优秀的日历插件,不仅支持多种调用模式,还支持日期范围限制. 常规的调用比较简单,如下所示: 1 <input class="Wdate" ...

随机推荐

  1. IDEA使用正则表达式替换

    替换目标:为value添加函数『JSON.stringify()』 vars.put("_id",value); 表达式: //find: (vars.put\(\"_i ...

  2. 从零开始针对 .NET 应用的 DevOps 运营实践 - 运行环境搭建

    一.Overview 最近的一段时间,在公司里我都在进行基于 Jenkins 和 SonarQube 配合已有的 Gitlab 搭建部门的持续集成环境的工作,虽然之前有使用过 GitHub Actio ...

  3. shell-的特殊变量-难点理论

    一:shell的特殊变量-难点理论  1. $*和$@的区别例子     $* 将所有的命令行所有参数视为单个字符串,等同于"$1$2$3"     $@ 将命令行每个参数视为单独 ...

  4. .NET Standard 类库的使用技巧

    系列目录     [已更新最新开发文章,点击查看详细] 在前一篇博客<.NET Standard中配置TargetFrameworks输出多版本类库>中详细介绍了如何创建.配置.条件编译. ...

  5. 题解:洛谷P1357 花园

    题解:洛谷P1357 花园 Description 小 L 有一座环形花园,沿花园的顺时针方向,他把各个花圃编号为 \(1∼n\).花园 \(1\) 和 \(n\) 是相邻的. 他的环形花园每天都会换 ...

  6. java axis调用带有soap头(soapheader)的.net webservice

    使用axis调用.net带soapheader的webservice是如何实现的,现在贴出代码 <?xml version="1.0" encoding="utf- ...

  7. 【Azure微服务 Service Fabric 】在SF节点中开启Performance Monitor及设置抓取进程的方式

    前提条件 当我们观察到SF中某一个节点出现CPU不正常的情况,但是由于不能肉眼长期观察,所以可以通过开启Performance Monitor的方式来获取每一个进程的%Processer Time的方 ...

  8. 51node1256 乘法匿元(扩展欧几里得)

    #include<iostream> using namespace std; int gcd(int a,int b,int &x,int &y){ if (b==0){ ...

  9. node运行js获得输出的三种方式

    一.通过console.log输出(我最喜欢的) 1.js脚本 1.js var arguments = process.argv.splice(2); //获得入参 var a= arguments ...

  10. Python合集之Python开发环境在Windows系统里面搭建

    在上一个合集里面我们了解到了Python的基础信息及学习了Python对我们有什么用处,那么今天我们来了解一下,Python的开发环境该如何搭建.(注:Python的开发环境可以在Windows.MA ...