Browse Source

fix: calendar组件重构更新

songchenglin3 5 years ago
parent
commit
ed26405db2

+ 3 - 3
src/packages/actionsheet/actionsheet.scss

@@ -57,7 +57,7 @@
 
 .nut-actionsheet-cancel {
 	border-top: 1px solid $as-border-color;
-	color: $as-disable-color;
+	color: $text-black-3;
 }
 
 .nut-actionsheet-confirm {
@@ -66,11 +66,11 @@
 	color: $as-confirm-btn-color;
 	.confirm-btn{
 		width: 100%;
-		height: 40px;
+		height: 50px;
 		background: $as-confirm-btn-bg;
 		border-radius: 4px;
 		font-size: $as-base-font-size;
-		line-height: 40px;
+		line-height: 50px;
 		text-align: center;
 	}
 }

+ 435 - 0
src/packages/calendar/calendar-slot.vue

@@ -0,0 +1,435 @@
+<template>
+    <div class="nut-calendar" :class="!poppable ? 'nut-calendar-unpoppable' : ''">
+      <div class="nut-calendar-control">
+        <template v-if="poppable">
+          <span class="nut-calendar-cancel-btn" @click="closeActionSheet">×</span>
+          <div class="nut-calendar-title">{{ title || nutTranslate('lang.calendar.title') }}</div>
+        </template>
+        <div class="nut-calendar-week">
+          <span v-for="(item, index) of week" :key="index">{{ item }}</span>
+        </div>
+        <slot name="shortcut" slot-scope></slot>
+      </div>
+      <div class="nut-calendar-months" ref="months" @touchstart.stop="touchStart" @touchmove.stop.prevent="touchMove" @touchend.stop="touchEnd">
+        <div class="nut-calendar-months-panel" ref="monthsPanel">
+          <div class="nut-calendar-loading-tip">{{
+            !unLoadPrev ? nutTranslate('lang.calendar.loadPrevMonth') : nutTranslate('lang.calendar.noMoreMonth')
+          }}</div>
+          <div class="nut-calendar-month" v-for="(month, index) of monthsData" :key="index">
+            <div class="nut-calendar-month-title">{{ month.title }}</div>
+            <div class="nut-calendar-month-con">
+              <div class="nut-calendar-month-item" :class="type === 'range' ? 'month-item-range' : ''">
+                <template v-for="(day, i) of month.monthData">
+                  <div class="nut-calendar-month-day" :class="getClass(day, month)" :title="isStartTip(day, month)" :key="i" @click="chooseDay(day, month)">
+                    <span class="nut-calendar-day">{{ day.type == 'curr' ? day.day : '' }}</span>
+                    <em class="curr-tips" v-if="isCurrDay(month, day.day)"></em>
+                    <span class="nut-calendar-day-tip" v-if="isStartTip(day, month)">{{ nutTranslate('lang.calendar.start') }}</span>
+                    <span class="nut-calendar-day-tip" v-else-if="isEndTip(day, month)">{{ nutTranslate('lang.calendar.end') }}</span>
+                  </div>
+                </template>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="nut-calendar-btn"  v-if="poppable">
+        <div  class="nut-calendar-confirm-btn" @click="confirm">确定</div>
+      </div>
+    </div>
+</template>
+<script>
+import Utils from '../../utils/date.js';
+import locale from '../../mixins/locale';
+export default {
+  name: 'nut-calendar-slot',
+  mixins: [locale],
+  props: {
+    type: {
+      type: String,
+      default: 'one'
+    },
+    isAutoBackFill: {
+      type: Boolean,
+      default: false
+    },
+    poppable: {
+      type: Boolean,
+      default: true
+    },
+    title: {
+      type: String,
+      default: '日期选择'
+    },
+    defaultValue: {
+      type: String | Array,
+      default: null
+    },
+    startDate: {
+      type: String,
+      default: Utils.getDay(0)
+    },
+    endDate: {
+      type: String,
+      default: Utils.getDay(365)
+    }
+  },
+  watch: {
+    defaultValue: {
+      handler(val, oldValue) {
+        if (val) {
+          this.resetRender();
+        }
+      },
+      //immediate: true
+    }
+  },
+  data() {
+    const week = this.nutTranslate('lang.calendar.week');
+    return {
+      childIsVisible: false,
+      currDate: null,
+      week: week.split(','),
+      unLoadPrev: false,
+      touchParams: {
+        startY: 0,
+        endY: 0,
+        startTime: 0,
+        endTime: 0
+      },
+      transformY: 0,
+      scrollDistance: 0,
+      defaultData: null,
+      chooseData: [],
+      monthsData: [],
+      dayPrefix: 'nut-calendar-month-day'
+    };
+  },
+  computed: {
+    isRange: function() {
+      return this.type === 'range';
+    }
+  },
+  methods: {
+    isCurrDay(month, day) {
+      let date = `${month.curData[0]}-${month.curData[1]}-${day}`;
+      return Utils.isEqual(date, Utils.date2Str(new Date()));
+    },
+    isActive(day, month) {
+      return this.isRange && day.type == 'curr' && this.getClass(day, month) == 'nut-calendar-month-day-active';
+    },
+
+    isStartTip(day, month) {
+      if (this.isActive(day, month)) {
+        return this.isStart(this.getCurrDate(day, month));
+      } else {
+        return false;
+      }
+    },
+
+    isEndTip(day, month) {
+      return this.isActive(day, month);
+    },
+
+    getCurrData(type) {
+      let monthData = type == 'prev' ? this.monthsData[0] : this.monthsData[this.monthsData.length - 1];
+      let year = parseInt(monthData.curData[0]);
+      let month = parseInt(monthData.curData[1].toString().replace(/^0/, ''));
+      switch (type) {
+        case 'prev':
+          month == 1 && (year -= 1);
+          month = month == 1 ? 12 : --month;
+          break;
+        case 'next':
+          month == 12 && (year += 1);
+          month = month == 12 ? 1 : ++month;
+          break;
+      }
+      return [year, Utils.getNumTwoBit(month), monthData.curData[2]];
+    },
+
+    getDaysStatus(days, type) {
+      // 修复:当某个月的1号是周日时,月份下方会空出来一行
+      if (type == 'prev' && days >= 7) {
+        days -= 7;
+      }
+      return Array.from(Array(days), (v, k) => {
+        return {
+          day: k + 1,
+          type: type
+        };
+      });
+    },
+
+    getMonth(curData, type) {
+      let preMonthDays = Utils.getMonthPreDay(curData[0], curData[1]);
+      let currMonthDays = Utils.getMonthDays(curData[0], curData[1]);
+      let nextMonthDays = 42 - preMonthDays - currMonthDays;
+      let title = this.nutTranslate('lang.calendar.monthTitle', { year: curData[0], month: curData[1] });
+      let monthInfo = {
+        curData: curData,
+        title: title,
+        monthData: [...this.getDaysStatus(preMonthDays, 'prev'), ...this.getDaysStatus(currMonthDays, 'curr')]
+      };
+      if (type == 'next') {
+        if (
+          !this.endData ||
+          !Utils.compareDate(
+            `${this.endData[0]}-${this.endData[1]}-${Utils.getMonthDays(this.endData[0], this.endData[1])}`,
+            `${curData[0]}-${curData[1]}-${curData[2]}`
+          )
+        ) {
+          this.monthsData.push(monthInfo);
+        } 
+      } else {
+        if (!this.startData || !Utils.compareDate(`${curData[0]}-${curData[1]}-${curData[2]}`, `${this.startData[0]}-${this.startData[1]}-01`)) {
+          this.monthsData.unshift(monthInfo);
+        } else {
+          this.unLoadPrev = true;
+        }
+      }
+    },
+
+    getCurrDate(day, month, isRange) {
+      return isRange
+        ? month.curData[3] + '-' + month.curData[4] + '-' + Utils.getNumTwoBit(day.day)
+        : month.curData[0] + '-' + month.curData[1] + '-' + Utils.getNumTwoBit(day.day);
+    },
+
+    isStart(currDate) {
+      return Utils.isEqual(this.currDate[0], currDate);
+    },
+
+    isEnd(currDate) {
+      return Utils.isEqual(this.currDate[1], currDate);
+    },
+
+    splitDate(date) {
+      return date.split('-');
+    },
+
+    getClass(day, month, isRange) {
+      let currDate = this.getCurrDate(day, month, isRange);
+      if (day.type == 'curr') {
+        if ((!this.isRange && Utils.isEqual(this.currDate, currDate)) || (this.isRange && (this.isStart(currDate) || this.isEnd(currDate)))) {
+          return `${this.dayPrefix}-active`;
+        } else if ((this.startDate && Utils.compareDate(currDate, this.startDate)) || (this.endDate && Utils.compareDate(this.endDate, currDate))) {
+          return `${this.dayPrefix}-disabled`;
+        } else if (
+          this.isRange & (this.currDate.length == 2) &&
+          Utils.compareDate(this.currDate[0], currDate) &&
+          Utils.compareDate(currDate, this.currDate[1])
+        ) {
+          return `${this.dayPrefix}-choose`;
+        } else {
+          return null;
+        }
+      } else {
+        return `${this.dayPrefix}-disabled`;
+      }
+    },
+
+    chooseDay(day, month, isFirst, isRange) {
+      if (this.getClass(day, month, isRange) != `${this.dayPrefix}-disabled`) {
+        let days = [...month.curData];
+        days = isRange ? days.splice(3) : days.splice(0, 3);
+        days[2] = typeof day.day == 'number' ? Utils.getNumTwoBit(day.day) : day.day;
+        days[3] = `${days[0]}-${days[1]}-${days[2]}`;
+        days[4] = Utils.getWhatDay(days[0], days[1], days[2]);
+        if (!this.isRange) {
+          this.currDate = days[3];
+          this.chooseData = [...days];
+        } else {
+          if (this.currDate.length == 2) {
+            this.currDate = [days[3]];
+          } else {
+            if (Utils.compareDate(this.currDate[0], days[3])) {
+              this.currDate.push(days[3]);
+            } else {
+              this.currDate.unshift(days[3]);
+            }
+          }
+          if (this.chooseData.length == 2 || !this.chooseData.length) {
+            this.chooseData = [...days];
+          } else {
+            if (Utils.compareDate(this.chooseData[3], days[3])) {
+              this.chooseData = [[...this.chooseData], [...days]];
+            } else {
+              this.chooseData = [[...days], [...this.chooseData]];
+            }
+          }
+        }
+        if (this.isAutoBackFill && !isFirst) {
+          this.confirm();
+        }
+      }
+    },
+
+    confirm() {
+      if ((this.isRange && this.chooseData.length == 2) || !this.isRange) {
+        this.$emit('choose', this.chooseData);
+        if (this.poppable) {
+          this.childIsVisible = false;
+          this.$emit('update');
+        }
+      }
+    },
+
+    resetRender() {
+      this.chooseData.splice(0);
+      this.monthsData.splice(0);
+      this.scrollDistance = 0;
+      this.translateY = 0;
+      this.setTransform(this.scrollDistance);
+      this.initData();
+    },
+
+    closeActionSheet() {
+      
+      if (this.poppable) {
+        this.childIsVisible = false;
+        this.$emit('update');
+        this.$emit('close');
+      }
+      this.resetRender();
+    },
+
+    touchStart(event) {
+      let changedTouches = event.changedTouches[0];
+      this.touchParams.startY = changedTouches.pageY;
+      this.touchParams.startTime = event.timestamp || Date.now();
+      this.transformY = this.scrollDistance;
+    },
+
+    touchMove(event) {
+      //event.preventDefault();
+      let changedTouches = event.changedTouches[0];
+      this.touchParams.lastY = changedTouches.pageY;
+      this.touchParams.lastTime = event.timestamp || Date.now();
+      let move = this.touchParams.lastY - this.touchParams.startY;
+      if (Math.abs(move) < 5) {
+        return false;
+      }
+      this.setMove(move);
+    },
+
+    touchEnd(event) {
+      let changedTouches = event.changedTouches[0];
+      this.touchParams.lastY = changedTouches.pageY;
+      this.touchParams.lastTime = event.timestamp || Date.now();
+      let move = this.touchParams.lastY - this.touchParams.startY;
+      if (Math.abs(move) < 5) {
+        return false;
+      }
+      let updateMove = move + this.transformY;
+      let h = this.$refs.months.offsetHeight;
+      let offsetHeight = this.$refs.monthsPanel.offsetHeight;
+       
+      if (updateMove > 0) {
+        this.getMonth(this.getCurrData('prev'), 'prev');
+      } else if (updateMove < -offsetHeight + h * 2) {
+        this.getMonth(this.getCurrData('next'), 'next');
+        if (Math.abs(move) >= 300) {
+          this.getMonth(this.getCurrData('next'), 'next');
+        }
+      }
+
+      let moveTime = this.touchParams.lastTime - this.touchParams.startTime;
+      if (moveTime <= 300) {
+        move = move * 2;
+        moveTime = moveTime + 1000;
+        this.setMove(move, 'end', moveTime);
+      } else {
+        this.setMove(move, 'end');
+      }
+    },
+
+    setTransform(translateY = 0, type, time = 1000) {
+      if (type === 'end') {
+        this.$refs.monthsPanel.style.webkitTransition = `transform ${time}ms cubic-bezier(0.19, 1, 0.22, 1)`;
+      } else {
+        this.$refs.monthsPanel.style.webkitTransition = '';
+      }
+
+      this.$refs.monthsPanel.style.webkitTransform = `translateY(${translateY}px)`;
+      this.scrollDistance = translateY;
+    },
+
+    setMove(move, type, time) {
+      let updateMove = move + this.transformY;
+      let h = this.$refs.months.offsetHeight;
+
+      let offsetHeight = this.$refs.monthsPanel.offsetHeight;
+      if (type === 'end') {
+        // 限定滚动距离
+        if (updateMove > 0) {
+          updateMove = 0;
+        }
+        if (updateMove < 0 && updateMove < -offsetHeight + h) {
+          updateMove = -offsetHeight + h;
+        }
+        if (offsetHeight <= h && this.monthsData.length == 1) {
+          updateMove = 0;
+        }
+        let endMove = updateMove;
+        this.setTransform(endMove, type, time);
+      } else {
+        if (updateMove > 0 && updateMove > 100) {
+          updateMove = 100;
+        }
+        if (updateMove < -offsetHeight + h - 100 && this.monthsData.length > 1) {
+          updateMove = -offsetHeight + h - 100;
+        }
+        if (updateMove < 0 && updateMove < -100 && this.monthsData.length == 1) {
+          updateMove = -100;
+        }
+        this.setTransform(updateMove);
+      }
+    },
+
+    initData() {
+      this.startData = this.startDate ? this.splitDate(this.startDate) : null;
+      this.endData = this.endDate ? this.splitDate(this.endDate) : null;
+      if (!this.defaultValue) {
+        this.currDate = this.isRange ? [Utils.date2Str(new Date()), Utils.getDay(1)] : Utils.date2Str(new Date());
+      } else {
+        this.currDate = this.isRange ? [...this.defaultValue] : this.defaultValue;
+      }
+
+      if (this.isRange) {
+        if (this.startDate && Utils.compareDate(this.currDate[0], this.startDate)) {
+          this.currDate.splice(0, 1, this.startDate);
+        }
+        if (this.endDate && Utils.compareDate(this.endDate, this.currDate[1])) {
+          this.currDate.splice(1, 1, this.endDate);
+        }
+        this.defaultData = [...this.splitDate(this.currDate[0]), ...this.splitDate(this.currDate[1])];
+      } else {
+        if (this.startDate && Utils.compareDate(this.currDate, this.startDate)) {
+          this.currDate = this.startDate;
+        } else if (this.endDate && !Utils.compareDate(this.currDate, this.endDate)) {
+          this.currDate = this.endDate;
+        }
+        this.defaultData = [...this.splitDate(this.currDate)];
+      }
+
+      this.getMonth(this.defaultData, 'next');
+
+      let i = 1;
+      do {
+        this.getMonth(this.getCurrData('next'), 'next');
+      } while (i++ < 4);
+
+      if (this.isRange) {
+        this.chooseDay({ day: this.defaultData[2], type: 'curr' }, this.monthsData[0], true);
+        this.chooseDay({ day: this.defaultData[5], type: 'curr' }, this.monthsData[0], true, true);
+      } else {
+        this.chooseDay({ day: this.defaultData[2], type: 'curr' }, this.monthsData[0], true);
+      }
+    }
+  },
+
+  mounted() {
+    this.initData();
+  }
+};
+</script>

+ 141 - 62
src/packages/calendar/calendar.scss

@@ -2,86 +2,132 @@
 @import '../../styles/animation/slide-right';
 
 .nut-calendar {
-	position: fixed;
-	top: 0;
-	left: 0;
-	bottom: 0;
-	width: 100%;
-	height: 100%;
-	overflow: hidden;
-	// height: 80%;
+	// height: 333px;
+	// padding-top: 103px;
+	// padding-bottom: 78px;
+	height: 514px;
 	background-color: #fff;
-	font-size: $font-size-base;
+	font-size: $font-size-title-normal;
+	color: $text-black-1;
 	display: flex;
 	flex-direction: column;
-	padding-top: 72px;
 	overflow: hidden;
-	z-index: 1000001;
+	position: relative;
+	font-family: $font-family;
+	&.nut-calendar-unpoppable{
+		height: 396px;
+		.nut-calendar-control{
+			height: 50px;
+			margin-bottom: 9px;
+		}
+		.nut-calendar-week {
+			height: 49px;
+			border-bottom: 1px solid $split-line-color;
+			line-height: 49px;
+		}
+		.nut-calendar-month-title {
+			padding-top: 7px !important;
+		}
+		.nut-calendar-shortcut{
+			bottom: -42px;
+		}
+	}
 }
 
 .nut-calendar-control {
-	position: absolute;
-	left: 0;
-	top: 0;
-	height: 70px;
+	// position: absolute;
+	// left: 0;
+	// top: 0;
+	// right: 0;
+	height: 103px;
 	width: 100%;
 	text-align: center;
 	background-color: #fff;
-	//border-bottom: 1px solid $light-color;
 	z-index: 1;
-
-	.nut-calendar-cancel-btn,
-	.nut-calendar-confirm-btn {
-		width: 60px;
+	position: relative;
+	.nut-calendar-cancel-btn {
+		padding: 0 20px;
 		color: $primary-color;
 		position: absolute;
 		top: 0;
-		line-height: 40px;
-	}
-
-	.nut-calendar-confirm-btn {
 		right: 0;
+		line-height: 47px;
+		color: $text-black-4;
 	}
-
-	.nut-calendar-cancel-btn {
-		left: 0;
-	}
-
 	.nut-calendar-title {
 		margin: 0 60px;
-		line-height: 40px;
+		line-height: 47px;
 		overflow: hidden;
 		text-overflow: ellipsis;
 		white-space: nowrap;
 	}
-
 	.nut-calendar-week {
 		display: flex;
-		//border-top: 1px solid $light-color;
-		height: 30px;
+		height: 55px;
+		justify-content: center;
 		text-align: center;
-		line-height: 30px;
-
+		line-height: 55px;
+		color: $text-black-2;
+		font-size: 15px;
+		border-top: 1px solid $split-line-color;
 		span {
+			//width: 52px;
 			flex: 1;
-
-			&:first-child,
-			&:last-child {
-				color: $primary-color;
-			}
 		}
 	}
 }
 
+.nut-calendar-btn{
+	height: 78px;
+	width: 100%;
+	background-color: #fff;
+	z-index: 1;
+	position: relative;
+	// position: absolute;
+	// left: 0;
+	// bottom: 0;
+	// right: 0;
+	.nut-calendar-confirm-btn{
+		height: 48px;
+		margin: 0 15px 30px 15px;
+		border-radius: 4px;
+		background-color: $primary-color-jd-red;
+		color: #fff;
+		text-align: center;
+		line-height: 48px;
+		font-size: $font-size-title-normal;
+	}
+}
+.nut-calendar-shortcut{
+	position: absolute;
+	right: 13px;
+	bottom: -27px;
+	div{
+		width: 68px;
+		height: 28px;
+		background: rgba(255,255,255,1);
+		border: 1px solid $split-line-color;
+		border-radius: 23px;
+		font-size: $font-size-display-normal;
+		color: $text-black-2;
+		line-height: 28px;
+	}
+}
 .nut-calendar-months {
 	width: 100%;
 	flex: 1;
-
+	height: 333px;
+	font-size: $font-size-body-normal;
+	
 	.nut-calendar-months-panel {
-		padding-bottom: 10px;
 		position: relative;
 		width: 100%;
 		height: auto;
+		div:nth-of-type(2){
+			.nut-calendar-month-title {
+				padding-top: 0;
+			}
+		}
 	}
 
 	.nut-calendar-loading-tip {
@@ -92,53 +138,86 @@
 		top: -50px;
 		left: 0;
 		right: 0;
-		color: $text-color;
-		font-size: $font-size-small;
+		color: $text-black-4;
+		font-size: $font-size-display-large;
 	}
 
 	.nut-calendar-month-title {
-		height: 30px;
-		line-height: 30px;
-		text-align: center;
-		background-color: $body-background;
+		height: 23px;
+		line-height: 23px;
+		text-align: left;
+		padding-top: 7px;
+		padding-bottom: 2px;
+		padding-left: 20px;
 	}
 
 	.nut-calendar-month-con {
 		overflow: hidden;
-		// .nut-calendar-month-item{
-		//     display: flex;
-		// }
+		.nut-calendar-month-item {
+			div:nth-child(7n+0),
+			div:nth-child(7n + 1) {
+				color: $text-black-4;
+			}
+		}
+		.month-item-range{
+			.nut-calendar-month-day{
+				height: 60px;
+				margin-bottom: 2px;
+			}
+			div[class*="nut-calendar-month-day-active"]{
+				&[title="true"]{
+					border-radius: 4px 0 0 4px;
+				}
+				border-radius: 0 4px 4px 0;
+			}
+		}
+
 		.nut-calendar-month-day {
 			//flex: 1;
 			float: left;
 			width: 14.28%;
-			height: 56px;
+			//width: 52px;
+			height: 52px;
 			display: flex;
 			align-items: center;
 			justify-content: center;
 			flex-direction: column;
-			//font-size: $font-size-large;
+			margin-bottom: 10px;
+			position: relative;
+			font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
+			.curr-tips{
+				width: 4px;
+				height: 4px;
+				border-radius: 50%;
+				background-color: $primary-color-jd-red;
+				position: absolute;
+				top: 36px;
+				left: 50%;
+				margin-left: -2px;
+			}
 			&-active {
-				background-color: $primary-color;
-				color: #fff;
+				border-radius: 4px;
+				background-color: $primary-color-jd-red;
+				color: #fff !important;
 			}
-
 			&-disabled {
-				color: $disabled-bg;
+				color: $text-black-4 !important;
 			}
 
 			&-choose {
-				background-color: mix($primary-color, #fff, 20%);
-				color: #fff;
+				background-color: #FFEFEB;
+				color: $primary-color-jd-red !important;
 			}
 
-			span {
-				padding: 3px 0;
+			.nut-calendar-day {
+				padding: 4px 0;
 			}
 
 			.nut-calendar-day-tip {
-				font-size: $font-size-small;
+				font-size: $font-size-display-small;
+				line-height: 1;
 			}
 		}
 	}
 }
+

+ 64 - 403
src/packages/calendar/calendar.vue

@@ -1,441 +1,102 @@
 <template>
-  <transition :name="animation">
-    <div class="nut-calendar" v-show="childIsVisible">
-      <div class="nut-calendar-control">
-        <span class="nut-calendar-confirm-btn" @click="confirm" v-if="(type == 'range' && currDate && currDate.length == 2) || type != 'range'">{{
-          nutTranslate('lang.okBtnTxt')
-        }}</span>
-        <span class="nut-calendar-cancel-btn" @click="closeActionSheet">{{ nutTranslate('lang.cancelBtnTxt') }}</span>
-        <div class="nut-calendar-title">{{ title || nutTranslate('lang.calendar.title') }}</div>
-        <div class="nut-calendar-week">
-          <span v-for="(item, index) of week" :key="index">{{ item }}</span>
-        </div>
-      </div>
-      <div class="nut-calendar-months" @touchstart.stop="touchStart" @touchmove.stop.prevent="touchMove" @touchend.stop="touchEnd">
-        <div class="nut-calendar-months-panel" ref="months">
-          <div class="nut-calendar-loading-tip">{{
-            !unLoadPrev ? nutTranslate('lang.calendar.loadPrevMonth') : nutTranslate('lang.calendar.noMoreMonth')
-          }}</div>
-          <div class="nut-calendar-month" v-for="(month, index) of monthsData" :key="index">
-            <div class="nut-calendar-month-title">{{ month.title }}</div>
-            <div class="nut-calendar-month-con">
-              <div class="nut-calendar-month-item">
-                <template v-for="(day, i) of month.monthData">
-                  <div class="nut-calendar-month-day" :class="getClass(day, month)" :key="i" @click="chooseDay(day, month)">
-                    <span>{{ day.type == 'curr' ? day.day : '' }}</span>
-                    <span class="nut-calendar-day-tip" v-if="isStartTip(day, month)">{{ nutTranslate('lang.calendar.start') }}</span>
-                    <span class="nut-calendar-day-tip" v-else-if="isEndTip(day, month)">{{ nutTranslate('lang.calendar.end') }}</span>
-                  </div>
-                </template>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </transition>
+  <nut-popup
+      v-model="childIsVisible"
+      position="bottom"
+      round
+      @click-overlay="closeActionSheet" 
+      v-if="poppable"
+    > 
+    <nut-calendar-slot props ref="mychild" 
+      :type="type"
+      :is-auto-back-fill="isAutoBackFill"
+      :poppable="poppable"
+      :title="title"
+      :default-value="defaultValue"
+      :start-date="startDate"
+      :end-date="endDate"
+      @update="update" 
+      @close="close" 
+      @choose="choose"
+    >
+      <div slot="shortcut" class="nut-calendar-shortcut">
+	      <slot name="shortcut"></slot>
+	    </div>
+    </nut-calendar-slot>
+  </nut-popup>
+  <nut-calendar-slot v-else  
+    :type="type"
+    :is-auto-back-fill="isAutoBackFill"
+    :poppable="poppable"
+    :title="title"
+    :default-value="defaultValue"
+    :start-date="startDate"
+    :end-date="endDate"
+    @close="close" 
+    @choose="choose"
+  >
+    <div slot="shortcut" class="nut-calendar-shortcut">
+	      <slot name="shortcut"></slot>
+	    </div>
+  </nut-calendar-slot>
 </template>
 <script>
-import Utils from '../../utils/date.js';
-import locale from '../../mixins/locale';
+import nutcalendarslot from './calendar-slot.vue';
 export default {
   name: 'nut-calendar',
-  mixins: [locale],
+  components: {
+    [nutcalendarslot.name]: nutcalendarslot
+  },
   props: {
     type: {
-      type: String,
-      default: 'one'
-    },
-    animation: {
-      type: String,
-      default: 'nutSlideUp'
+      type: String
     },
     isAutoBackFill: {
-      type: Boolean,
-      default: false
+      type: Boolean
     },
-    isOpenRangeSelect: {
+    poppable: {
       type: Boolean,
-      default: false
+      default: true
     },
     isVisible: {
-      type: Boolean,
-      default: false
+      type: Boolean
     },
     title: {
       type: String
     },
     defaultValue: {
-      type: String | Array,
-      default: null
+      type: String | Array
     },
     startDate: {
-      type: String,
-      //default: null
-      default: Utils.getDay(0)
+      type: String
     },
     endDate: {
-      type: String,
-      //default: null
-      default: Utils.getDay(365)
-    }
-  },
-  watch: {
-    isVisible(newValue, oldValue) {
-      this.childIsVisible = newValue;
-    },
-    defaultValue: {
-      handler(oldValue, val) {
-        if (val) {
-          this.resetRender();
-        }
-      },
-      immediate: true
+      type: String
     }
   },
   data() {
-    const week = this.nutTranslate('lang.calendar.week');
     return {
-      childIsVisible: false,
-      currDate: null,
-      week: week.split(','),
-      unLoadPrev: false,
-      unLoadNext: false,
-      touchParams: {
-        startY: 0,
-        endY: 0,
-        startTime: 0,
-        endTime: 0
-      },
-      transformY: 0,
-      scrollDistance: 0,
-      defaultData: null,
-      chooseData: [],
-      monthsData: [],
-      dayPrefix: 'nut-calendar-month-day'
-    };
+      childIsVisible: false
+    }
   },
-  computed: {
-    isRange: function() {
-      return this.type === 'range';
+  watch: {
+    isVisible(newValue, oldValue) {
+        this.childIsVisible = newValue;
     }
   },
   methods: {
-    isActive(day, month) {
-      return this.isRange && day.type == 'curr' && this.getClass(day, month) == 'nut-calendar-month-day-active';
-    },
-
-    isStartTip(day, month) {
-      if (this.isActive(day, month)) {
-        return this.isStart(this.getCurrDate(day, month));
-      } else {
-        return false;
-      }
-    },
-
-    isEndTip(day, month) {
-      return this.isActive(day, month);
-    },
-
-    getCurrData(type) {
-      let monthData = type == 'prev' ? this.monthsData[0] : this.monthsData[this.monthsData.length - 1];
-      let year = parseInt(monthData.curData[0]);
-      let month = parseInt(monthData.curData[1].toString().replace(/^0/, ''));
-      switch (type) {
-        case 'prev':
-          month == 1 && (year -= 1);
-          month = month == 1 ? 12 : --month;
-          break;
-        case 'next':
-          month == 12 && (year += 1);
-          month = month == 12 ? 1 : ++month;
-          break;
-      }
-      return [year, Utils.getNumTwoBit(month), monthData.curData[2]];
-    },
-
-    getDaysStatus(days, type) {
-      // 修复:当某个月的1号是周日时,月份下方会空出来一行
-      if (type == 'prev' && days >= 7) {
-        days -= 7;
-      }
-      return Array.from(Array(days), (v, k) => {
-        return {
-          day: k + 1,
-          type: type
-        };
-      });
-    },
-
-    getMonth(curData, type) {
-      let preMonthDays = Utils.getMonthPreDay(curData[0], curData[1]);
-      let currMonthDays = Utils.getMonthDays(curData[0], curData[1]);
-      let nextMonthDays = 42 - preMonthDays - currMonthDays;
-      let title = this.nutTranslate('lang.calendar.monthTitle', { year: curData[0], month: curData[1] });
-      let monthInfo = {
-        curData: curData,
-        title: title,
-        monthData: [...this.getDaysStatus(preMonthDays, 'prev'), ...this.getDaysStatus(currMonthDays, 'curr')]
-      };
-      if (type == 'next') {
-        if (
-          !this.endData ||
-          !Utils.compareDate(
-            `${this.endData[0]}-${this.endData[1]}-${Utils.getMonthDays(this.endData[0], this.endData[1])}`,
-            `${curData[0]}-${curData[1]}-${curData[2]}`
-          )
-        ) {
-          this.monthsData.push(monthInfo);
-        } else {
-          this.unLoadNext = true;
-        }
-      } else {
-        if (!this.startData || !Utils.compareDate(`${curData[0]}-${curData[1]}-${curData[2]}`, `${this.startData[0]}-${this.startData[1]}-01`)) {
-          this.monthsData.unshift(monthInfo);
-        } else {
-          this.unLoadPrev = true;
-        }
-      }
-    },
-
-    getCurrDate(day, month, isRange) {
-      return isRange
-        ? month.curData[3] + '-' + month.curData[4] + '-' + Utils.getNumTwoBit(day.day)
-        : month.curData[0] + '-' + month.curData[1] + '-' + Utils.getNumTwoBit(day.day);
-    },
-
-    isStart(currDate) {
-      return Utils.isEqual(this.currDate[0], currDate);
-    },
-
-    isEnd(currDate) {
-      return Utils.isEqual(this.currDate[1], currDate);
-    },
-
-    splitDate(date) {
-      return date.split('-');
-    },
-
-    getClass(day, month, isRange) {
-      let currDate = this.getCurrDate(day, month, isRange);
-      if (day.type == 'curr') {
-        if ((!this.isRange && Utils.isEqual(this.currDate, currDate)) || (this.isRange && (this.isStart(currDate) || this.isEnd(currDate)))) {
-          return `${this.dayPrefix}-active`;
-        } else if ((this.startDate && Utils.compareDate(currDate, this.startDate)) || (this.endDate && Utils.compareDate(this.endDate, currDate))) {
-          return `${this.dayPrefix}-disabled`;
-        } else if (
-          this.isRange & (this.currDate.length == 2) &&
-          Utils.compareDate(this.currDate[0], currDate) &&
-          Utils.compareDate(currDate, this.currDate[1])
-        ) {
-          return `${this.dayPrefix}-choose`;
-        } else {
-          return null;
-        }
-      } else {
-        return `${this.dayPrefix}-disabled`;
-      }
-    },
-
-    chooseDay(day, month, isFirst, isRange) {
-      if (this.getClass(day, month, isRange) != `${this.dayPrefix}-disabled`) {
-        let days = [...month.curData];
-        days = isRange ? days.splice(3) : days.splice(0, 3);
-        days[2] = typeof day.day == 'number' ? Utils.getNumTwoBit(day.day) : day.day;
-        days[3] = `${days[0]}-${days[1]}-${days[2]}`;
-        days[4] = Utils.getWhatDay(days[0], days[1], days[2]);
-        if (!this.isRange) {
-          this.currDate = days[3];
-          this.chooseData = [...days];
-        } else {
-          if (this.currDate.length == 2) {
-            this.currDate = [days[3]];
-          } else {
-            if (Utils.compareDate(this.currDate[0], days[3])) {
-              this.currDate.push(days[3]);
-            } else {
-              this.currDate.unshift(days[3]);
-            }
-          }
-          if (this.chooseData.length == 2 || !this.chooseData.length) {
-            this.chooseData = [...days];
-          } else {
-            if (Utils.compareDate(this.chooseData[3], days[3])) {
-              this.chooseData = [[...this.chooseData], [...days]];
-            } else {
-              this.chooseData = [[...days], [...this.chooseData]];
-            }
-          }
-        }
-        if (this.isAutoBackFill && !isFirst) {
-          this.confirm();
-        }
-      }
-    },
-
-    confirm() {
-      if ((this.isRange && this.chooseData.length == 2) || !this.isRange) {
-        this.$emit('choose', this.chooseData);
-        this.childIsVisible = false;
-        this.$emit('update:is-visible', false);
-      }
-    },
-
-    resetRender() {
-      this.chooseData.splice(0);
-      this.monthsData.splice(0);
-      this.scrollDistance = 0;
-      this.translateY = 0;
-      this.setTransform(this.scrollDistance);
-      this.initData();
-    },
-
     closeActionSheet() {
-      this.childIsVisible = false;
-      this.$emit('update:is-visible', false);
-      this.$emit('close');
-      this.resetRender();
-    },
-
-    touchStart(event) {
-      let changedTouches = event.changedTouches[0];
-      this.touchParams.startY = changedTouches.pageY;
-      this.touchParams.startTime = event.timestamp || Date.now();
-      this.transformY = this.scrollDistance;
-    },
-
-    touchMove(event) {
-      //event.preventDefault();
-      let changedTouches = event.changedTouches[0];
-      this.touchParams.lastY = changedTouches.pageY;
-      this.touchParams.lastTime = event.timestamp || Date.now();
-      let move = this.touchParams.lastY - this.touchParams.startY;
-      if (Math.abs(move) < 5) {
-        return false;
-      }
-      this.setMove(move);
+      this.$refs.mychild.closeActionSheet();
     },
-
-    touchEnd(event) {
-      let changedTouches = event.changedTouches[0];
-      this.touchParams.lastY = changedTouches.pageY;
-      this.touchParams.lastTime = event.timestamp || Date.now();
-      let move = this.touchParams.lastY - this.touchParams.startY;
-      if (Math.abs(move) < 5) {
-        return false;
-      }
-      let updateMove = move + this.transformY;
-      let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
-      let offsetHeight = this.$refs.months.offsetHeight;
-      if (updateMove > 0) {
-        this.getMonth(this.getCurrData('prev'), 'prev');
-      } else if (updateMove < -offsetHeight + h * 2) {
-        this.getMonth(this.getCurrData('next'), 'next');
-        if (Math.abs(move) >= 300) {
-          this.getMonth(this.getCurrData('next'), 'next');
-        }
-      }
-
-      let moveTime = this.touchParams.lastTime - this.touchParams.startTime;
-      if (moveTime <= 300) {
-        move = move * 2;
-        moveTime = moveTime + 1000;
-        this.setMove(move, 'end', moveTime);
-      } else {
-        this.setMove(move, 'end');
-      }
-    },
-
-    setTransform(translateY = 0, type, time = 1000) {
-      if (type === 'end') {
-        this.$refs.months.style.webkitTransition = `transform ${time}ms cubic-bezier(0.19, 1, 0.22, 1)`;
-        //this.$refs.months.style.transition = `transform ${time}ms cubic-bezier(0.19, 1, 0.22, 1)`;
-      } else {
-        this.$refs.months.style.webkitTransition = '';
-        //this.$refs.months.style.transition = '';
-      }
-
-      this.$refs.months.style.webkitTransform = `translateY(${translateY}px)`;
-      //this.$refs.months.style.transform = `translateY(${translateY}px)`;
-      this.scrollDistance = translateY;
+    update() {
+      this.childIsVisible = false;
     },
-
-    setMove(move, type, time) {
-      let updateMove = move + this.transformY;
-      let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
-
-      let offsetHeight = this.$refs.months.offsetHeight;
-      if (type === 'end') {
-        // 限定滚动距离
-        if (updateMove > 0) {
-          updateMove = 0;
-        }
-        if (updateMove < 0 && updateMove < -offsetHeight + h - 70) {
-          updateMove = -offsetHeight + h - 70;
-        }
-        if (offsetHeight <= h && this.monthsData.length == 1) {
-          updateMove = 0;
-        }
-        let endMove = updateMove;
-        this.setTransform(endMove, type, time);
-      } else {
-        if (updateMove > 0 && updateMove > 100) {
-          updateMove = 100;
-        }
-        if (updateMove < -offsetHeight + h - 170 && this.monthsData.length > 1) {
-          updateMove = -offsetHeight + h - 170;
-        }
-        if (updateMove < 0 && updateMove < -100 && this.monthsData.length == 1) {
-          updateMove = -100;
-        }
-        this.setTransform(updateMove);
-      }
+    close() {
+      this.$emit('close');
     },
-
-    initData() {
-      this.startData = this.startDate ? this.splitDate(this.startDate) : null;
-      this.endData = this.endDate ? this.splitDate(this.endDate) : null;
-      if (!this.defaultValue) {
-        this.currDate = this.isRange ? [Utils.date2Str(new Date()), Utils.getDay(2)] : Utils.date2Str(new Date());
-      } else {
-        this.currDate = this.isRange ? [...this.defaultValue] : this.defaultValue;
-      }
-
-      if (this.isRange) {
-        if (this.startDate && Utils.compareDate(this.currDate[0], this.startDate)) {
-          this.currDate.splice(0, 1, this.startDate);
-        }
-        if (this.endDate && Utils.compareDate(this.endDate, this.currDate[1])) {
-          this.currDate.splice(1, 1, this.endDate);
-        }
-        this.defaultData = [...this.splitDate(this.currDate[0]), ...this.splitDate(this.currDate[1])];
-      } else {
-        if (this.startDate && Utils.compareDate(this.currDate, this.startDate)) {
-          this.currDate = this.startDate;
-        } else if (this.endDate && !Utils.compareDate(this.currDate, this.endDate)) {
-          this.currDate = this.endDate;
-        }
-        this.defaultData = [...this.splitDate(this.currDate)];
-      }
-
-      this.getMonth(this.defaultData, 'next');
-
-      let i = 1;
-      do {
-        this.getMonth(this.getCurrData('next'), 'next');
-      } while (i++ < 4);
-
-      if (this.isRange) {
-        this.chooseDay({ day: this.defaultData[2], type: 'curr' }, this.monthsData[0], true);
-        this.chooseDay({ day: this.defaultData[5], type: 'curr' }, this.monthsData[0], true, true);
-      } else {
-        this.chooseDay({ day: this.defaultData[2], type: 'curr' }, this.monthsData[0], true);
-      }
+    choose(param) {
+      this.close();
+      this.$emit('choose', param);
     }
-  },
-
-  mounted() {
-    this.initData();
   }
 };
 </script>

+ 99 - 88
src/packages/calendar/demo.vue

@@ -1,75 +1,76 @@
 <template>
   <div class="demo-list">
-    <nut-noticebar :closeMode="true" v-if="!isMobile"
-      >此 Demo 在 PC 端浏览器与移动端浏览器体验差异较大,建议在 Android 或 iOS 设备上体验。
-    </nut-noticebar>
-    <h4>基本用法</h4>
-    <nut-cell :showIcon="true" @click.native="switchPicker('isVisible')">
-      <span slot="title"><label>日期选择</label></span>
-      <span slot="sub-title">没有默认日期~~~</span>
-      <div slot="desc" class="selected-option">
-        <span class="show-value">{{ date ? `${date} ${dateWeek}` : '请选择日期' }}</span>
-      </div>
-    </nut-cell>
-    <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible2')">
-      <span slot="title"><label>日期选择</label></span>
-      <span slot="sub-title">有默认日期,选择后自动回填的~~~</span>
-      <div slot="desc" class="selected-option">
-        <span class="show-value">{{ date2 ? date2 : '请选择日期' }}</span>
-      </div>
-    </nut-cell>
-    <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible1')">
-      <span slot="title"><label>日期区间选择</label></span>
-      <span slot="sub-title">有默认日期~~~</span>
-      <div slot="desc" class="selected-option">
-        <span class="show-value">{{ date1 ? `${date1[0]}至${date1[1]}` : '请选择日期' }}</span>
-      </div>
-    </nut-cell>
-    <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible3')">
-      <span slot="title"><label>日期区间选择</label></span>
-      <span slot="sub-title">不限制开始结束时间~~~</span>
-      <div slot="desc" class="selected-option">
-        <span class="show-value">{{ date3 ? `${date3[0]}至${date3[1]}` : '请选择日期' }}</span>
-      </div>
-    </nut-cell>
-    <!-- demo-->
-    <nut-calendar
-      :is-visible.sync="isVisible"
-      :default-value="date"
-      @close="switchPickerClose('isVisible')"
-      @choose="setChooseValue"
-      :start-date="`2018-10-11`"
-      :end-date="`2020-11-11`"
-    >
-    </nut-calendar>
-    <nut-calendar
-      :is-visible.sync="isVisible2"
-      :default-value="date2"
-      :is-auto-back-fill="true"
-      @close="switchPickerClose('isVisible2')"
-      @choose="setChooseValue2"
-    >
-    </nut-calendar>
-    <nut-calendar
-      :is-visible.sync="isVisible1"
-      :default-value="date1"
-      type="range"
-      :start-date="null"
-      :end-date="null"
-      @close="switchPickerClose('isVisible1')"
-      @choose="setChooseValue1"
-    >
-    </nut-calendar>
-    <nut-calendar
-      :is-visible.sync="isVisible3"
-      :default-value="date3"
-      type="range"
-      :start-date="null"
-      :end-date="null"
-      @close="switchPickerClose('isVisible3')"
-      @choose="setChooseValue3"
-    >
-    </nut-calendar>
+    <h4>基础样式</h4>
+    <div>
+      <nut-cell 
+        :showIcon="true" 
+        title="选择日期"
+        :desc="date ? `${date} ${dateWeek}` : '请选择'"
+        @click.native="openSwitch('isVisible')">
+      </nut-cell>
+      <nut-calendar
+        :is-visible="isVisible"
+        :default-value="date"
+        @close="closeSwitch('isVisible')"
+        @choose="setChooseValue"
+        :start-date="`2019-10-11`"
+        :end-date="`2020-11-11`"
+      >
+      </nut-calendar>
+    </div>
+
+    <div>
+      <nut-cell 
+        :showIcon="true"  
+        title="选择时间段"
+        :desc="date1 ? `${date1[0]}至${date1[1]}` : '请选择'"
+        @click.native="openSwitch('isVisible1')">
+      </nut-cell>
+
+      <nut-calendar
+        :is-visible="isVisible1"
+        :default-value="date1"
+        type="range"
+        :start-date="`2019-12-22`"
+        :end-date="`2021-01-08`"
+        @close="closeSwitch('isVisible1')"
+        @choose="setChooseValue1"
+      >
+      </nut-calendar>
+    </div>
+    <div>
+      <nut-cell 
+        :showIcon="true" 
+        title="快捷选择区间"
+        :desc="date3 ? `${date3[0]}至${date3[1]}` : '请选择'"
+        @click.native="openSwitch('isVisible3')">
+      </nut-cell>
+    </div>
+    <div>
+      <nut-calendar
+        :is-visible="isVisible3"
+        :default-value="date3"
+        type="range"
+        :start-date="null"
+        :end-date="null"
+        @close="closeSwitch('isVisible3')"
+        @choose="setChooseValue3"
+      >
+      <div slot="shortcut" @click="chooseShortcutMode">近一周</div>
+      </nut-calendar>
+    </div>
+
+    <h4>平铺样式</h4>
+    <div class="">
+      <nut-calendar
+        :poppable="false"
+        :is-visible="isVisible2"
+        :default-value="date2"
+        :is-auto-back-fill="true"
+        @choose="setChooseValue2"
+      >
+      </nut-calendar>
+    </div>
   </div>
 </template>
 
@@ -79,40 +80,50 @@ export default {
   data() {
     return {
       isVisible: false,
-      isVisible1: false,
-      isVisible2: false,
-      isVisible3: false,
       date: null,
       dateWeek: null,
-      date1: ['2018-12-22', '2019-01-08'],
-      date2: Utils.getDay(30),
-      date3: null
+
+      date2: '2020-07-08',
+      isVisible2: true,
+
+      isVisible1: false,
+      date1: ['2019-12-23', '2019-12-26'],
+
+      isVisible3: false,
+      date3:null
     };
   },
   methods: {
-    switchPickerClose(param) {
-      console.log('close:' + param);
-    },
-    switchPicker(param) {
+    openSwitch(param) {
       this[`${param}`] = true;
     },
+
+    closeSwitch(param) {
+      this[`${param}`] = false;
+    },
+
     setChooseValue(param) {
       this.date = param[3];
       this.dateWeek = param[4];
     },
-    setChooseValue1(param) {
-      this.date1 = [...[param[0][3], param[1][3]]];
-    },
+
     setChooseValue2(param) {
       this.date2 = param[3];
+      console.log(this.date2);
+    },
+
+    setChooseValue1(param) {
+      this.date1 = [...[param[0][3], param[1][3]]];
     },
+
     setChooseValue3(param) {
       this.date3 = [...[param[0][3], param[1][3]]];
     },
-    setChooseValue4(param) {},
-    setChooseValue5(param) {}
+
+    chooseShortcutMode() {
+      this.date3 =[...[Utils.getDay(0), Utils.getDay(6)]];
+      this.closeSwitch('isVisible3');
+    }
   }
 };
-</script>
-
-<style lang="scss" scoped></style>
+</script>

+ 152 - 70
src/packages/calendar/doc.md

@@ -1,100 +1,176 @@
 # Calendar 日历
 
-## 基本用法
+## 基础样式
 
-日期选择(不带默认日期
+选择日期
 
 ```html
-<nut-calendar 
-    :is-visible.sync="isVisible"
+<nut-cell 
+    :showIcon="true" 
+    title="选择日期"
+    :desc="date ? `${date} ${dateWeek}` : '请选择'"
+    @click.native="openSwitch('isVisible')">
+</nut-cell>
+<nut-calendar
+    :is-visible="isVisible"
     :default-value="date"
-    @close="switchPickerClose('isVisible')"
+    @close="closeSwitch('isVisible')"
     @choose="setChooseValue"
-    :start-date="`2018-10-11`"
+    :start-date="`2019-10-11`"
     :end-date="`2020-11-11`"
->
+    >
 </nut-calendar>
 ```
+```javascript
+import Utils from '../../utils/date.js';
+export default {
+  data() {
+    return {
+      isVisible: false,
+      date: null,
+      dateWeek: null
+    };
+  },
+  methods: {
+    openSwitch(param) {
+      this[`${param}`] = true;
+    },
 
-日期选择(有默认日期,选择后自动回填)
+    closeSwitch(param) {
+      this[`${param}`] = false;
+    },
 
-```html
-<nut-calendar 
-    :is-visible.sync="isVisible2"
-    :default-value="date2"
-    :is-auto-back-fill="true"
-    @close="switchPickerClose('isVisible2')"
-    @choose="setChooseValue2"
->
-</nut-calendar>
+    setChooseValue(param) {
+      this.date = param[3];
+      this.dateWeek = param[4];
+    }
+  }
+};
 ```
 
-日期区间选择(有默认日期)
+选择时间段
 
 ```html
-<nut-calendar 
-    :is-visible.sync="isVisible1"
+<nut-cell 
+    :showIcon="true"  
+    title="选择时间段"
+    :desc="date1 ? `${date1[0]}至${date1[1]}` : '请选择'"
+    @click.native="openSwitch('isVisible1')">
+</nut-cell>
+<nut-calendar
+    :is-visible="isVisible1"
     :default-value="date1"
     type="range"
-    @close="switchPickerClose('isVisible1')"
+    :start-date="`2019-12-22`"
+    :end-date="`2021-01-08`"
+    @close="closeSwitch('isVisible1')"
     @choose="setChooseValue1"
 >
 </nut-calendar>
 ```
+```javascript
+import Utils from '../../utils/date.js';
+export default {
+  data() {
+    return {
+      isVisible1: false,
+      date1: ['2019-12-23', '2019-12-26']
+    };
+  },
+  methods: {
+    openSwitch(param) {
+      this[`${param}`] = true;
+    },
+
+    closeSwitch(param) {
+      this[`${param}`] = false;
+    },
+
+    setChooseValue1(param) {
+      this.date1 = [...[param[0][3], param[1][3]]];
+    }
+  }
+};
+```
 
-日期区间选择(不限制开始结束时间)
+快捷选择区间
 
 ```html
-<nut-calendar 
-    :is-visible.sync="isVisible3"
+<nut-cell 
+    :showIcon="true" 
+    title="快捷选择区间"
+    :desc="date3 ? `${date3[0]}至${date3[1]}` : '请选择'"
+    @click.native="openSwitch('isVisible3')">
+</nut-cell>
+<nut-calendar
+    :is-visible="isVisible3"
     :default-value="date3"
     type="range"
     :start-date="null"
     :end-date="null"
-    :animation="`nutSlideUp`"
-    @close="switchPickerClose('isVisible3')"
+    @close="closeSwitch('isVisible3')"
     @choose="setChooseValue3"
->
+    >
+    <div slot="shortcut" @click="chooseShortcutMode">近一周</div>
 </nut-calendar>
 ```
-
 ```javascript
+import Utils from '../../utils/date.js';
 export default {
-    data() {
-        return {
-            isVisible: false,
-            isVisible1: false,
-            isVisible2: false,
-            isVisible3: false,
-            date: null,
-            dateWeek: null,
-            date1: ['2018-12-22', '2019-01-08'],
-            date2: Utils.getDay(30), // 当前日期之后的30天
-            date3: null
-            
-        };
+  data() {
+    return {
+      isVisible3: false,
+      date3:null
+    };
+  },
+  methods: {
+    openSwitch(param) {
+      this[`${param}`] = true;
+    },
+
+    closeSwitch(param) {
+      this[`${param}`] = false;
+    },
+
+    setChooseValue3(param) {
+      this.date3 = [...[param[0][3], param[1][3]]];
     },
-    methods: {
-        switchPickerClose(param){
-            console.log('close:' + param)
-        },
-        switchPicker(param) {
-            this[`${param}`] = true;
-        },
-        setChooseValue(param) {
-            this.date = param[3];
-            this.dateWeek = param[4];
-        },
-        setChooseValue1(param) {
-            this.date1 = [...[param[0][3],param[1][3]]];
-        },
-        setChooseValue2(param) {
-            this.date2 = param[3];
-        },
-        setChooseValue3(param) {
-            this.date3 = [...[param[0][3],param[1][3]]];
-        }
+
+    chooseShortcutMode() {
+      this.date3 =[...[Utils.getDay(0), Utils.getDay(6)]];
+      this.closeSwitch('isVisible3');
+    }
+  }
+};
+```
+
+## 平铺样式
+
+```html
+<nut-calendar
+    :poppable="false"
+    :is-visible="isVisible2"
+    :default-value="date2"
+    :is-auto-back-fill="true"
+    @choose="setChooseValue2"
+    >
+</nut-calendar>
+```
+```javascript
+import Utils from '../../utils/date.js';
+export default {
+  data() {
+    return {
+      date2: '2020-07-08',
+      isVisible2: true
+    };
+  },
+  methods: {
+    setChooseValue2(param) {
+      this.date2 = param[3];
+      console.log(this.date2);
     }
+  }
 };
 ```
 
@@ -103,18 +179,24 @@ export default {
 | 字段 | 说明 | 类型 | 默认值
 |----- | ----- | ----- | ----- 
 | type | 类型,日期选择'one',区间选择'range' | String | 'one'
-| isVisible | 是否可见(注意:绑定时必须`:is-visible.sync`,加sync修饰符) | Boolean | false
-| animation | 日历进入方向,右滑'nutSlideRight', 上拉'nutSlideUp' | String | 'nutSlideRight' 
-| isAutoBackFill | 是否自动回填 | Boolean | false
-| isOpenRangeSelect | 是否开启区间选择 | Boolean | false
-| title | 显示标题 | String | ‘选择日期’
-| defaultValue | 默认值,日期选择String格式,区间选择Array格式 | String || Array | null
-| startDate | 开始日期, 如果不限制开始日期传null | String | 今天
-| default | 结束日期,如果不限制结束日期传null | String | 距离今天五个月
+| is-visible | 是否可见 | Boolean | false
+| poppable | 是否弹窗状态展示 | Boolean | true
+| is-auto-back-fill | 自动回填,仅在poppable为true可用 | Boolean | false
+| is-open-range-select | 是否开启区间选择 | Boolean | false
+| title | 显示标题 | String | ‘日期选择’
+| default-value | 默认值,日期选择String格式,区间选择Array格式 | String / Array | null
+| start-date | 开始日期, 如果不限制开始日期传null | String | 今天
+| end-date | 结束日期,如果不限制结束日期传null | String | 距离今天五个月
+
+## Slot
+
+| 名称 | 说明 
+|----- | ----- 
+| shortcut | 自定义快捷选择区间文案
 
 ## Event
 
 | 字段 | 说明 | 回调参数 
 |----- | ----- | ----- 
 | choose | 选择之后或是点击确认按钮触发 | 日期数组(包含年月日和星期) 
-| close | 关闭时触发 | -
+| close | 关闭时触发 | -

+ 2 - 2
src/packages/datepicker/datepicker.vue

@@ -228,7 +228,7 @@ export default {
       let cacheMonths = [];
       for (var i = 1; i <= 12; i++) {
         if (!(year == this.startDateArr[0] && i < this.startDateArr[1]) && !(year == this.endDateArr[0] && i > this.endDateArr[1])) {
-          cacheMonths.push(`${i}${this.chinese[1]}`);
+          cacheMonths.push(`${this.isShowChinese ? i : Utils.getNumTwoBit(i)}${this.chinese[1]}`);
         }
       }
       return cacheMonths;
@@ -242,7 +242,7 @@ export default {
           !(year == this.startDateArr[0] && month == parseInt(this.startDateArr[1]) && (k + 1) <  parseInt(this.startDateArr[2])) &&
           !(year == this.endDateArr[0] && month == parseInt(this.endDateArr[1]) && (k + 1) > parseInt(this.endDateArr[2]))
         ) {
-          return `${k + 1}${this.chinese[2]}`;
+          return `${this.isShowChinese ? k + 1 : Utils.getNumTwoBit(k + 1)}${this.chinese[2]}`;
         }
       });
       return days.filter(item => item);

+ 20 - 23
src/packages/datepicker/demo.vue

@@ -6,7 +6,7 @@
     <h4>选择年月日</h4>
     <nut-cell 
       :showIcon="true"  
-      title="每列不显示年/月/日"
+      title="每列不显示中文(年/月/日"
       :desc="date ? date : '请选择'"
       @click.native="switchPicker('isVisible')">
     </nut-cell>
@@ -19,6 +19,24 @@
       @choose="setChooseValue"
     ></nut-datepicker>
 
+    <h4>选择时间</h4>
+    <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible3')">
+      <span slot="title">
+        <label>选择时间</label>
+      </span>
+      <div slot="desc" class="selected-option">
+        <span class="show-value">{{ time ? `${time}` : '请选择' }}</span>
+      </div>
+    </nut-cell>
+    <nut-datepicker
+      :is-visible="isVisible3"
+      type="time"
+      title="选择时间"
+      @close="switchPicker('isVisible3')"
+      @choose="setChooseValue3"
+      defaultValue="01:07"
+    ></nut-datepicker>
+
     <h4>限制开始结束时间</h4>
     <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible2')">
       <span slot="title">
@@ -39,26 +57,6 @@
       @choose="setChooseValue2"
     ></nut-datepicker>
 
-    <h4>选择时间</h4>
-    <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible3')">
-      <span slot="title">
-        <label>12时间制</label>
-      </span>
-      <div slot="desc" class="selected-option">
-        <span class="show-value">{{ time ? `${time} ${amOrPm}` : '请选择' }}</span>
-      </div>
-    </nut-cell>
-    <nut-datepicker
-      :is-visible="isVisible3"
-      type="time"
-      title="选择时间"
-      @close="switchPicker('isVisible3')"
-      @choose="setChooseValue3"
-      :is-use12-hours="true"
-      defaultValue="01:07"
-      :is-am="false"
-    ></nut-datepicker>
-
     <h4>限制开始结束小时</h4>
     <nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible4')">
       <span slot="title">
@@ -129,8 +127,7 @@ export default {
       this.datetime = param[5];
     },
     setChooseValue3(param) {
-      this.amOrPm = param[2] == '上午' ? 'AM' : 'PM';
-      this.time = param[3];
+      this.time = param[2];
     },
     setChooseValue4(param) {
       this.time1 = param[3];

+ 32 - 34
src/packages/datepicker/doc.md

@@ -39,90 +39,88 @@ export default {
 };
 ```
 
-## 限制开始结束时间
+
+## 选择时间
 
 ```html
-<nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible2')">
+<nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible3')">
     <span slot="title">
-    <label>日期时间选择</label>
+    <label>选择时间</label>
     </span>
     <div slot="desc" class="selected-option">
-    <span class="show-value">{{ datetime ? datetime : '请选择' }}</span>
+    <span class="show-value">{{ time ? `${time}` : '请选择' }}</span>
     </div>
 </nut-cell>
 <nut-datepicker
-    :is-visible="isVisible2"
-    title="选择日期时间"
-    type="datetime"
-    startDate="2000-11-10 12:08"
-    endDate="2030-10-05 10:04"
-    defaultValue="2018-11-02 11:08"
-    @close="switchPicker('isVisible2')"
-    @choose="setChooseValue2"
+    :is-visible="isVisible3"
+    type="time"
+    title="选择时间"
+    @close="switchPicker('isVisible3')"
+    @choose="setChooseValue3"
+    defaultValue="01:07"
 ></nut-datepicker>
 ```
 ```javascript
 export default {
   data() {
     return {
-      isVisible2: false,
-      time: '01:07'
+      isVisible3: false,
+      time: '01:07',
     };
   },
   methods: {
     switchPicker(param) {
       this[`${param}`] = !this[`${param}`];
     },
-    setChooseValue2(param) {
-      this.datetime = param[5];
+    setChooseValue3(param) {
+      this.time = param[2];
     }
   }
 };
 ```
 
-## 选择时间
+## 限制开始结束时间
 
 ```html
-<nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible3')">
+<nut-cell :showIcon="true" :isLink="true" @click.native="switchPicker('isVisible2')">
     <span slot="title">
-    <label>12时间制</label>
+    <label>日期时间选择</label>
     </span>
     <div slot="desc" class="selected-option">
-    <span class="show-value">{{ time ? `${time} ${amOrPm}` : '请选择' }}</span>
+    <span class="show-value">{{ datetime ? datetime : '请选择' }}</span>
     </div>
 </nut-cell>
 <nut-datepicker
-    :is-visible="isVisible3"
-    type="time"
-    title="选择时间"
-    @close="switchPicker('isVisible3')"
-    @choose="setChooseValue3"
-    :is-use12-hours="true"
-    defaultValue="01:07"
-    :is-am="false"
+    :is-visible="isVisible2"
+    title="选择日期时间"
+    type="datetime"
+    startDate="2000-11-10 12:08"
+    endDate="2030-10-05 10:04"
+    defaultValue="2018-11-02 11:08"
+    @close="switchPicker('isVisible2')"
+    @choose="setChooseValue2"
 ></nut-datepicker>
 ```
 ```javascript
 export default {
   data() {
     return {
-      isVisible3: false,
-      datetime: '2018-11-02 11:08',
-      amOrPm: 'PM'
+      isVisible2: false,
+      time: '01:07'
     };
   },
   methods: {
     switchPicker(param) {
       this[`${param}`] = !this[`${param}`];
     },
-    setChooseValue3(param) {
-      this.amOrPm = param[2] == '上午' ? 'AM' : 'PM';
-      this.time = param[3];
+    setChooseValue2(param) {
+      this.datetime = param[5];
     }
   }
 };
 ```
 
+
 ## 限制开始结束小时
 
 ```html

+ 0 - 3
src/packages/picker/picker.vue

@@ -27,8 +27,6 @@
   </nut-popup>
 </template>
 <script>
-import nutactionsheet from '../actionsheet/actionsheet.vue';
-import '../actionsheet/actionsheet.scss';
 import nutpickerslot from './picker-slot.vue';
 import locale from '../../mixins/locale';
 export default {
@@ -57,7 +55,6 @@ export default {
     }
   },
   components: {
-    [nutactionsheet.name]: nutactionsheet,
     [nutpickerslot.name]: nutpickerslot
   },
   data() {