Vue 实现的一个日历

由于项目需要,实现一个日历组件,直接上代码,实现逻辑代码里有注释:

<template>
  <div class="calendar">
    <div class="now-mouth">{{displayDate}}</div>
    <div class="calendar-title">
      <div class="calendar-select">
        <div class="calendar-select-row" v-for="(week,index) in weekName " :key="index">
            <input class="checkbox" :ref="'week_'+index" type="checkbox" :name="week" @change="checked('week',index)" />
        </div>
        <div class="calendar-select-row"></div>
      </div>
      <div class="calendar-select">
         <div class="calendar-select-row" v-for="(week, index) in weekName" :key="index">
           <div class="week" > {{week}}</div>
         </div>
         <div class="calendar-select-row">
            <input class="checkbox" ref="checkAll" type="checkbox"  @change="checkAll" />
         </div>
      </div>
    </div>
    <div class="calendar-body">
        <div v-for="(week, weeKIndex) in calendarDay" :key="weeKIndex" >
           <div class="calendar-select">
            <div
              class="calendar-select-row"
              v-for="(day, dayIndex) in week" :key="dayIndex"
              :class="{isSelected: day.select}"
              @click="onClick(day)"
              >
              <div class="day" v-show="day.day">
                {{day.day}}
              </div>
            </div>
            <div class="calendar-select-row">
              <input class="checkbox" type="checkbox"
                :ref="'row_'+weeKIndex"
                v-show="week[0].day || week[6].day"
                @change="checked('row',weeKIndex)"
              />
            </div>
          </div>
        </div>
    </div>
  </div>
</template>

<script>
/**
*  Canlendar Module
* ----------------------
* Author:zoboy
* Date: 2019.06.12
*/
import moment from 'moment'
export default {
  name: 'Canlendar',
  components: {},
  data () {
    return {
      displayDate: '',
      nowDay: '',
      calendarDay: [],
      checkedDay: [],
      weekName: ['日', '一', '二', '三', '四', '五', '六']
    }
  },
  props: {
    mouth: String
  },
  mounted () {
    this.createCalendar(this.mouth)
  },
  created () {},
  methods: {
    onClick (day) {
      if (day && day.day) this.$emit('onClick', day)
    },
    checked (target, index) {
      let checkRef = target + '_' + index
      let check = this.$refs[checkRef][0].checked
      this.calendarDay.forEach(week => {
        week.forEach(day => {
          if (day && day.day && day[target] === index) day.select = check
        })
      })
    },
    checkWork (isOnWork, select) {
      this.calendarDay.forEach(week => {
        week.forEach(day => {
          if (day && day.day) {
            if (isOnWork && (day.week > 0 && day.week < 6)) {
              day.select = select
            } else if (!isOnWork && (day.week === 0 || day.week === 6)) {
              day.select = select
            }
          }
        })
      })
    },
    checkAll () {
      let check = this.$refs.checkAll.checked
      this.calendarDay.forEach(week => {
        week.forEach(day => {
          if (day && day.day) day.select = check
        })
      })
    },
    createCalendar (mouth) {
      if (mouth) this.nowDay = moment(mouth).format('YYYY-MM')
      else this.nowDay = moment().format('YYYY-MM')
      this.displayDate = moment(this.nowDay).format('YYYY年MM月')
      this.calendarDay = this.getCurrMonthDays(this.nowDay)
    },
    getCurrMonthDays (theDay) {
      // 获取当前月的第一天
      let start = moment(theDay).add('month', 0).format('YYYY-MM') + '-01'
      // 获取上一个月的总天数
      let lastMonthDays = moment(this.date).subtract(1, 'month').daysInMonth()
      // 构造日历的42个格子
      let daysArr = [[], [], [], [], [], []]
      // 获取当前月的第一天是星期几
      let currentWeekday = moment(start).format('E')
      // 获取当前月的总天数
      let nowMouthDays = moment(theDay).daysInMonth()
      for (let i = 0; i < 7; i++) { // 每一周
        // 虚拟天数,确定第一行第一列的值(上个月的总天数-当前月第一天的星期几(1)=26就是第一个格子的值,后面的一次类推)
        let virtualDay = (lastMonthDays - currentWeekday) + i + 1
        for (let j = 0; j < daysArr.length; j++) { // 每一天
          daysArr[j][i] = this.getDay(i, j, start, virtualDay + (j * 7), lastMonthDays, nowMouthDays) // 每一行*7
        }
      }
      return daysArr
    },
    getDay (week, row, start, day, lastMonthDays, nowMouthDays, index) {
      let dayObj = {}
      if (day <= lastMonthDays) { // 上一月 (*<32)
        // return day
        dayObj = {'day': ''}
      } else if (day <= (lastMonthDays + nowMouthDays)) { // 本月(*<=(31+30))
        let dayNum = day - lastMonthDays
        let date = moment(start).add(dayNum - 1, 'days').format('YYYY-MM-DD')
        dayObj = {
          day: dayNum,
          date: date,
          week: week,
          row: row,
          isToday: new Date(date).getTime() === new Date(moment().format('YYYY-MM-DD')).getTime(),
          select: false
        }
      } else { // 下一月 (*>(31+30))
        // return day - (lastMonthDays + nowMouthDays)
        dayObj = {'day': ''}
      }
      return dayObj
    }
  },
  computed: {},
  watch: {
    mouth (newMouth) {
      this.createCalendar(newMouth)
    },
    calendarDay: {
      handler (canlendar) {
        this.checkedDay = []
        canlendar.forEach(week => {
          week.forEach(day => {
            if (day && day.day) {
              if (day.select) this.checkedDay.push(day)
              // else {
              //   console.log(day.week, day.row)
              //   let weekRef = 'week_' + day.week
              //   let rowRef = 'row_' + day.row
              //   this.$refs[weekRef][0].checked = false
              //   this.$refs[rowRef][0].checked = false
              //   this.$refs.checkAll.checked = false
              // }
            }
          })
        })
        console.log(this.checkedDay)
      },
      deep: true
    }
  }
}
</script>
<style lang="scss" scoped>
$base-light-color: #f2f2f2;
.calendar{
  margin: 15px;
  width: 248px;
  height: 224px;
  display: flex;
  flex-direction: column;
  border-top: 1px solid darken($base-light-color, 5%);
  border-left: 1px solid darken($base-light-color, 5%);
  .now-mouth{
     border-bottom: 1px solid darken($base-light-color, 5%);
     border-right: 1px solid darken($base-light-color, 5%);
  }
  .calendar-title{
    .calendar-week{
      min-width: 35px;
    }

  }
  .calendar-select{
      display: flex;
      flex-direction: row;
      .calendar-select-row{
        min-width: 30px;
        min-height: 25px;
        border-right: 1px solid darken($base-light-color, 5%);
        border-bottom: 1px solid darken($base-light-color, 5%);
        // &:last-child {
        //   border-right: none;
        // }
        .checkbox{
          margin-top: 6px;
          margin-left: 7px;
        }
        .week{
          margin-top: 6px;
          margin-left: 7px;
        }

      }
  }

  .calendar-body{
    .day {
      margin-top: 4px;
      margin-left: 9px;
      cursor:pointer;
    }
    .isSelected {
        background-color: #1260ad;
      }
  }
}
</style>

效果图:

发布了48 篇原创文章 · 获赞 60 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/u011051912/article/details/91952865