用vant封装一个选择日历组件

235 阅读1分钟
<template>
  <div ref="choose" class="choose-time">
    <van-popup v-model="show" position="bottom" @click-overlay="close" :get-container="() => $refs.choose">
      <div class="center-date">
        <van-button class="left-btn" @click.native="arrowLeft" :disabled="isLeftDisabled">
          <van-icon name="arrow-left" />
        </van-button>
        <span>{{ centerDate }}</span>
        <van-button class="right-btn" @click.native="arrowRight" :disabled="isRightDisabled">
          <van-icon name="arrow" />
        </van-button>
      </div>

      <van-calendar
        class="calendar"
        ref="calendar"
        :show-title="false"
        :poppable="false"
        :show-confirm="false"
        :show-mark="false"
        :round="false"
        :row-height="45"
        :lazy-render="true"
        :min-date="minDate"
        :max-date="maxDate"
        :formatter="formatter"
        @select="slecetDay"
        :getContainer="() => $refs.choose"
      />
    </van-popup>
  </div>
</template>

<script>
import moment from 'moment'

// 禁止触摸移动
// const handler = e => {
//   e.preventDefault()
// }
export default {
  name: 'ChooseDate',
  data() {
    return {
      show: false,
      minDate: new Date(),
      maxDate: new Date(),
      defaultDate: new Date(),
      cont: 0,
      year: new Date().getFullYear(),
      month: new Date().getMonth(),
      nowDay: new Date().getDate(),
      isRightDisabled: false,
      isLeftDisabled: false,
      beforeMonthList: this.xDate(), // 近12个月的日期数组
      selectedDate: '', // 选择的日期
      nowDate: new Date(),
      canScroll: false
    }
  },
  computed: {
    centerDate() {
      return `${this.defaultDate.getFullYear() + '年' + (this.defaultDate.getMonth() + 1) + '月'}`
    }
  },
  watch: {
    // 解决popup滚动穿透的问题
    // show: val => {
    //   if (val) {
    //     document.addEventListener('touchmove', handler, { passive: false })
    //   } else {
    //     document.removeEventListener('touchmove', handler, { passive: false })
    //   }
    // }
  },
  created() {
    this.setMinMaxDay()
  },

  methods: {
    dblclick(e) {
      console.log(e)
    },
    // 关闭窗口
    close() {
      this.show = false
    },
    // 选择日期
    slecetDay(day, e) {
      this.selectedDate = moment(day).format('YYYY-MM-DD')
      setTimeout(() => {
        this.show = false
        this.$emit('updateDate', this.selectedDate)
      }, 200)
    },
    // 设置显示月份可选择的天数区间
    setMinMaxDay() {
      // console.log(this.beforeMonthList)
      //   最小日期
      var firstDay = new Date(this.nowDate)
      firstDay.setDate(1)
      this.minDate = new Date(this.year, this.month + this.cont, firstDay.getDate())
      //   最大日期
      var endDate = new Date(this.nowDate)
      endDate.setMonth(this.defaultDate.getMonth() + 1, 1)
      endDate.setDate(0)
      this.maxDate = new Date(this.year, this.month + this.cont, endDate.getDate())
      //   超过当前日期近12个月禁用切换按钮
      if (
        (this.maxDate.getFullYear() === this.year && this.maxDate.getMonth() >= this.month) ||
        this.maxDate.getFullYear() > this.year
      ) {
        this.isRightDisabled = true
      } else {
        this.isRightDisabled = false
      }
      if (`${this.minDate.getFullYear()}-${this.minDate.getMonth() + 1}` === this.beforeMonthList[0]) {
        this.isLeftDisabled = true
      } else {
        this.isLeftDisabled = false
      }
    },
    // 获取近12月日期函数
    xDate() {
      var dataArr = []
      var data = new Date()
      // 获取到当前月份,设置月份
      data.setMonth(data.getMonth() + 1)
      for (var i = 0; i < 12; i++) {
        data.setMonth(data.getMonth() - 1) // 每次循环一次 月份值减1
        dataArr.push(data.getFullYear() + '-' + (data.getMonth() + 1))
      }
      return dataArr.reverse()
    },

    // 当前月上一个月
    arrowLeft() {
      this.cont--
      //   const lastDay = this.getCurrentMonthLast(new Date(this.year, this.month + this.cont))
      //   this.defaultDate = new Date(this.year, this.month + this.cont, lastDay)
      this.defaultDate = new Date(this.year, this.month + this.cont)
      this.setMinMaxDay()
    },
    // 当前月下一个月
    arrowRight() {
      this.cont++
      //   const lastDay = this.getCurrentMonthLast(new Date(this.year, this.month + this.cont))
      //   this.defaultDate = new Date(this.year, this.month + this.cont, lastDay)
      this.defaultDate = new Date(this.year, this.month + this.cont)
      this.setMinMaxDay()
    },
    // Vant日历日期添加法定节假日以及24节气
    formatter(day) {
      //   console.log(day)
      const nowY = this.nowDate.getFullYear()
      const nowM = this.nowDate.getMonth() + 1
      const nowD = this.nowDate.getDate()
      const _time = new Date(day.date)
      const y = _time.getFullYear()
      const m = _time.getMonth() + 1
      const d = _time.getDate()
      const w = _time.getDay()
      // 获取每个月的最后一天
      const lastDay = this.getCurrentMonthLast(day.date)
      //   改变周六周日显示颜色
      if (y === nowY && m === nowM && d === nowD) {
        day.className = 'weekendRed'
        day.text = '今'
      } else if (y === nowY && m === nowM && d > nowD) {
        day.type = 'disabled'
        if (d < 10) {
          day.text = '0' + d
        }
      } else if (d < 10 && w !== 0) {
        day.text = '0' + d
        day.type = 'disabled'
      } else if (d < 10) {
        day.text = '0' + d
      } else if (w === 0) {
        day.className = 'weekendRed'
      } else if (day.text === lastDay) {
        day.className = 'weekendRed'
      } else if (day.type === 'selected' && day.text === '01') {
        day.className = 'orther'
      } else {
        day.type = 'disabled'
      }
      return day
    },
    // 获取每月的最后一天函数
    getCurrentMonthLast(date) {
      var currentMonth = date.getMonth()

      var nextMonth = ++currentMonth

      var nextMonthFirstDay = new Date(date.getFullYear(), nextMonth, 1)

      var oneDay = 1000 * 60 * 60 * 24

      var lastTime = new Date(nextMonthFirstDay - oneDay)

      var month = parseInt(lastTime.getMonth() + 1)

      var day = lastTime.getDate()

      if (month < 10) {
        month = '0' + month
      }

      if (day < 10) {
        day = '0' + day
      }
      return day
    },
    // 展示日历
    showBox() {
      this.show = true
    },
    formatDate(date) {
      return `${date.getMonth() + 1}+${date.getDate()}`
    }
  }
}
</script>

<style lang="scss" scoped>
::v-deep .van-popup .van-popup--bottom {
  position: relative;
  .van-icon-arrow:before {
    position: absolute !important;
    top: 3.6rem;
    right: 1.2rem;
    font-size: 1.3rem;
  }
}
.right-btn {
  position: absolute !important;
  top: 32px;
  right: 44px;
  font-size: 24px;
  color: #666;
  border: 0px solid #000;
  background-color: transparent;
}
::v-deep .van-icon.van-icon-arrow {
  position: absolute;
  top: 0px;
  right: 0px;
  font-size: 24px;
  color: #666;
}
.left-btn {
  position: absolute;
  top: 32px;
  left: 44px;
  font-size: 24px;
  color: #666;
  border: 0px solid #000;
  background-color: transparent;
}
::v-deep .van-icon.van-icon-arrow-left {
  position: absolute;
  top: 0px;
  left: 0px;
  font-size: 24px;
  color: #666;
}
::v-deep .van-calendar__selected-day {
  font-family: PingFangSC-Medium;
  font-size: 30px;
  color: #ff6633;
  font-weight: 500;
  background-color: rgba(255, 102, 51, 0.3);
  border-radius: 50%;
}
::v-deep .van-calendar__selected-day.orther {
  font-family: PingFangSC-Medium;
  font-size: 30px;
  color: #333333;
  font-weight: 500;
  background-color: #fff;
  border-radius: 50%;
}
::v-deep .van-calendar__day.weekendRed {
  color: #333333;
  background-color: #fff;
}
::v-deep .van-calendar__days .everyDay {
  color: #cccccc !important;
  background-color: #fff;
}
::v-deep .van-calendar__weekday {
  background-color: #f9f9f9;
}
::v-deep .van-calendar__header-subtitle {
  height: 102px;
}
::v-deep .van-button::before {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100%;
  height: 100%;
  background-color: #fff;
  border: inherit;
  border-color: #000;
  border-radius: inherit;
  -webkit-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
  opacity: 0;
  content: ' ';
}
::v-deep .van-calendar__day--disabled {
  color: #c8c9cc;
  cursor: default;
  background-color: #fff;
}
::v-deep .van-calendar__days {
  background-color: #fff;
  // height: 343px;
  padding-bottom: 40px;
}
::v-deep .van-calendar__header-subtitle {
  display: none;
}
.center-date {
  height: 1.36rem;
  font-weight: 500;
  line-height: 1.17333rem;
  text-align: center;
  font-size: 0.37333rem;
  background-color: #fff;
}
::v-deep .hidden-scroll {
  overscroll-behavior-y: none !important;
}
</style>