自定义一个日历组件

  项目中需要一个日历,日历上挂载一些活动啥的,还有一些特殊的查询的处理,各大ui库也满足不了自己项目的需求,所以自己写一个,踩的坑也忘了,毕竟是很早之前写的,而且对于时间的处理和排布,还是有点复杂的。所以记录先吧,以防以后可以要用。

<template>
  <div class="calendar_box">
    <div class="calendar_month">
      <i class="cs-chevronleft" @click="pre()"></i>
      <span>{{currentYear + '' + currentMonth + ''}}</span>
      <i class="cs-chevronright" @click="next()"></i>
    </div>
    <div class="calendar_week">
      <div class="cal-cell1">周日</div>
      <div class="cal-cell1">周一</div>
      <div class="cal-cell1">周二</div>
      <div class="cal-cell1">周三</div>
      <div class="cal-cell1">周四</div>
      <div class="cal-cell1">周五</div>
      <div class="cal-cell1">周六</div>
    </div>
    <div class="calendar_days">
      <div class="calendar_week_days"
        v-for="(day, index) in days" :key="index">
        <div class="cal_month_day"
          v-for="(item, idx) in day" :key="idx">
          <span :class="{
            'disabled': item.disabled,
            'red': idx === 0 || idx === 6,
            'active': currentDayValue === item.value
          }">{{item.day}}</span>
          <div class="events_list" v-if="events[item.value]">
            <el-tooltip placement="top"
              v-for="(ev, i) in events[item.value]"
              :key="i"
              :content="ev.title">
              <router-link
              :to="toEventDetail(ev)"
              class="dot"
              :class="{
                'gray': parseInt(item.value) < parseInt(currentDayValue)
              }"></router-link>
            </el-tooltip>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
  import { getCalendarEventsApi } from '@/apis'
  export default {
    data () {
      return {
        currentDayValue: 0,
        currentMonth: 1,
        currentYear: 2020,
        days: [], // 日历数据
        events: {}, // 活动数据
        params: {} // 活动查询参数
      }
    },
    methods: {
      // 初始化日期
      initDate (datoObj) {
        let now = !datoObj ? new Date() : new Date(datoObj.y, datoObj.m, 1)
        // 获取当前时间
        let y = now.getFullYear()
        let m = now.getMonth()
        // let d = now.getDate()
        // 当月最后一天是几号
        let _lastDateOfMonth = new Date(y, m + 1, 0).getDate()
        // 当月第一天是周几
        let _firstDayWeekOfMonth = new Date(y, m, 1).getDay()
        // 上月最后一天是几号
        let _lastDayOfLastMonth = new Date(y, m, 0).getDate()

        let line = 0
        let temp = []
        for (let i = 1; i <= _lastDateOfMonth; i++) {
          let _day = new Date(y, m, i).getDay() // 返回星期几
          // 第一行
          if (_day === 0) {
            temp[line] = []
            // 如果当月第一天就是周天,取查询参数值
            if (_firstDayWeekOfMonth === 0) {
              this.params.start = this.formatValue(y, m + 1, 1)
            }
          } else if (i === 1) {
            let k = 0
            temp[line] = []
            k = _lastDayOfLastMonth - _firstDayWeekOfMonth + 1
            for (let j = 0; j < _firstDayWeekOfMonth; j++) {
              // 取查询参数值
              if (j === 0) {
                this.params.start = this.formatValue(y, m, k)
              }
              temp[line].push({
                day: k,
                disabled: true,
                value: this.formatValue(y, m, k)
              })
              k++
            }
          }

          temp[line].push({
            day: i,
            value: this.formatValue(y, m + 1, i)
          })

          // 到周六,并且行数小于5时换行
          if (_day === 6 && line < 5) {
            line++
            temp[line] = []
          }
          // 如果到了当月最后一天
          if (i === _lastDateOfMonth) {
            // 下个月的时间补位
            let next = 1
            let max = (line === 5 ? 6 : 13)
            let d = _day
            // 当最后一天是周六的时候,说明没占位,下个月占位需要为7位
            // 当最后一天不是周六的时候,说明占位了,那么下个月占位需要减1位
            if (_day === 6) {
              d = 0
              max = 7
            }
            for (; d < max; d++) {
              // 如果为周六,且行数小于5时候
              if (d === 6 && line < 5) {
                line++
                temp[line] = []
              }
              // 取查询参数值
              if (d === (max - 1)) {
                this.params.end = this.formatValue(y, m + 2, next)
              }
              temp[line].push({
                day: next,
                disabled: true,
                value: this.formatValue(y, m + 2, next)
              })
              next++
            }
          }
        }
        this.days = temp
        getCalendarEventsApi(this.params).then(res => {
          if (res.status === 200) {
            this.events = res.data
          }
        })
      },
      formatValue (y, m, d) {
        if (m > 12) {
          y += 1
          m = 1
        } else if (m < 1) {
          y -= 1
          m = 12
        }
        let _m = (m > 9 ? m : ('0' + m))
        let _d = (d > 9 ? d : ('0' + d))
        return y.toString() + _m + _d
      },
      // 向前
      pre () {
        this.currentMonth -= 1
        if (this.currentMonth < 1) {
          this.currentMonth = 12
          this.currentYear -= 1
        }
        this.initDate({ y: this.currentYear, m: this.currentMonth - 1 })
      },
      // 向后
      next () {
        this.currentMonth += 1
        if (this.currentMonth > 12) {
          this.currentMonth = 1
          this.currentYear += 1
        }
        this.initDate({ y: this.currentYear, m: this.currentMonth - 1 })
      },
      toEventDetail (item) {
        let _route = (item.productIds && item.productIds.length > 0) ? `/event/sale/${item.id}` : `/event/${item.id}`
        if (item.id === 76) {
          _route = '/dtc'
        }
        return _route
      }
    },
    mounted () {
      this.initDate()
      let _now = new Date()
      this.currentYear = _now.getFullYear()
      this.currentMonth = _now.getMonth() + 1
      let d = _now.getDate()
      this.currentDayValue = this.formatValue(this.currentYear, this.currentMonth, d)
    }
  }
</script>
<style lang="stylus" scoped>
.calendar_box{
  margin-left 20px
  width 530px
  box-shadow 0 0 12px 0 rgba(0,0,0,0.05)
  font-family: -apple-system,"Helvetica Neue",Helvetica,Arial,"PingFang SC","Hiragino Sans GB","WenQuanYi Micro Hei","Microsoft Yahei",sans-serif;
  font-size: 14px;
  color: #333;
  background-color: #fff;
  -webkit-font-smoothing: antialiased;
}
.calendar_month{
  border 1px solid #E1E1E1
  height 49px
  line-height 49px
  font-size 18px
  font-weight 700
  span{
    margin 0 30px
    vertical-align middle
  }
  i{
    cursor pointer
    vertical-align middle
    font-size 28px
  }
}
.calendar_week{
  display flex
  border 1px solid #E1E1E1
  padding 5px 0
  margin 1px 0
  .cal-cell1{
    flex 1
    font-weight: bolder
    text-align: center
  }
}
.calendar_week_days{
  display flex
  border-right 1px solid #E1E1E1
  .cal_month_day{
    flex 1
    height 50px
    text-align center
    border-left 1px solid #E1E1E1
    border-bottom 1px solid #E1E1E1
    cursor pointer
    span{
      display: inline-block;
      font-size: 20px;
      line-height 30px
      transition: all 0.3s ease-in-out;
      -webkit-transition: all 0.1s ease-in-out;
      &.disabled{
        opacity 0.25
      }
      &.red{
        color #D0021B
      }
      &.active{
        width 30px
        height 30px
        border-radius 50%
        background-color #e8fde7
        color darkgreen
      }
    }
  }
}
.events_list{
  height 16px
  overflow hidden
  .dot{
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: #7ED321;
    margin 0 1px
    &.gray{
      background-color #666666
    }
  }
}
</style>

 

posted @ 2020-05-15 16:02  古兰精  阅读(527)  评论(0编辑  收藏  举报