记一次写考勤日历组件(vue)

这是在工作的时候做的一个考勤日历功能,整体来说比较简单,记录在此,方便以后复盘

用到的组件有moment.js,有这个组件大大简化了一些时间的加减计算

先上整体效果:
记一次写考勤日历组件(vue)_第1张图片
ps:样式有点丑,没做调整
1.首先是HTML结构部分

  <div style="width: 500px;height: 500px;">
    <!--    标题、上月、下月-->
    <div class="width-100-per layout-side" style="height: 10%;">
      <div class="cursor-pointer layout-center leftRightBtn" @click="prevMonth">&lt;</div>
      <div class="height-100-per layout-center-top width-40-per">
        <div class="layout-center timeTitle">
          <span style="font-weight: bold">{{`${newDate.split('-')[0]}${newDate.split('-')[1]}月`}}</span>
        </div>
      </div>
      <div class="cursor-pointer layout-center leftRightBtn" @click="nextMonth">&gt;</div>
    </div>
    <!--    日期表-->
    <div class="width-100-per layout-left-top padding-10-px" style="height: calc(100% - 10%)">
      <!--      星期-->
      <div class="width-100-per layout-left-top" style="height: 10%">
        <div style="width: calc(100% / 7);" class="layout-center" v-for="(i,index) in weekArr" :key="index + i">{{i}}
        </div>
      </div>
      <!--      日期-->
      <div class="width-100-per layout-left-top" style="height: 90%">
        <template v-for="(i,index) in dateArr">
          <div class="layout-center tableCol" :style="{height: 'calc(100% / '+maxTableRow+')'}" :key="index"
               :class="{'topBorderNone':index<7,'rightBorderNone':(index+8)%7===0}">
            <div :title="i" class="width-100-per height-100-per layout-center" :class="{'checked':i===thisDate}" style="cursor: default;position: relative">
              <span>{{i === '' ? '' : Number(i.split('-')[2])}}</span>
              <div v-if="showDayStatus(i)" class="checkBadge"></div>
            </div>
          </div>
        </template>
      </div>
    </div>
  </div>

2.js部分

<script>
  import moment from 'moment'
  export default {
    data() {
      return {
        thisDate: moment().format('YYYY-MM-DD'),//当前时间
        thisMonthDays: '',//当月天数
        thisDateWeek: '',//当月第一天是星期几
        newDate: '',//标题展示时间
        dateArr: [],//日期数组,有则填日期,无则填‘’
        weekArr: ['七','一', '二', '三', '四', '五', '六'],
        checkArr: [
          {
            checkinginTime: '2020-03-28',
            ip: '111'
          },
          {
            checkinginTime: '2020-03-27',
            ip: '111'
          },
          {
            checkinginTime: '2020-03-26',
            ip: '111'
          }
        ],//已经打过卡的数组,由后端返回,这里写死
        maxTableRow: 0,//列固定7列,这是当月最大行数
      }
    },
    mounted() {
      this.calendarTable(this.thisDate);
    },
    computed: {
      //判断当天状态
      showDayStatus() {
        const that = this;
        return function (value) {
          if (!!value) {
            let flag = false;
            for (const ca of that.checkArr) {
              if ((ca.checkinginTime).indexOf(value) > -1) {
                flag = true
              }
            }
            return flag
          }
        }
      },
    },
    methods: {
      //绘制日历表格
      calendarTable(date) {
        const that = this;
        that.dateArr = [];
        that.newDate = date;
        let yearMonthDay = that.newDate.split('-');
        //当月天数
        that.thisMonthDays = moment(date).daysInMonth();
        //当月一号是星期几
        that.thisDateWeek = moment(date).date(1).weekday();
        let calendarArr = [];
        //往日历数组装每天的日期
        for (let i = 1; i < that.thisMonthDays + 1; i++) {
          calendarArr.push(yearMonthDay[0] + '-' + yearMonthDay[1] + '-' + (i < 10 ? '0' + i : i))
        }
        // 有当月一号是星期几根据规则往前面补空位
        for (let j = 0; j < that.thisDateWeek; j++) {
          calendarArr.unshift('')
        }
        // 表格列数固定为7列,获取最大行数
        let len = calendarArr.length;
        let arrRow = Math.ceil(len / 7);
        that.maxTableRow = arrRow;
        // 获取整个表格的格子个数,给多余的格子补空
        for (let k = 0; k < arrRow * 7 - len; k++) {
          calendarArr.push('')
        }
        that.dateArr = calendarArr;
      },
      //上个月
      prevMonth() {
        const that = this;
        let date = moment(that.newDate).subtract(1, 'months').format('YYYY-MM-DD');
        that.calendarTable(date)
      },
      // 下个月
      nextMonth() {
        const that = this;
        let date = moment(that.newDate).add(1, 'months').format('YYYY-MM-DD');
        that.calendarTable(date)
      },
    }
  }
</script>

ps:js部分基本都有注释,时间那一块详情要参考moment的官方文档了。代码基本可以原封不动的搬走,不清楚的地方自己打印出来看基本就明白了
3.css部分

  .timeTitle {
    margin-top: 1px;
    width: 100%;
    height: 100%;
    background: #FFCC38;
    color: black;
    transform: perspective(0.5rem) rotateX(-3deg)
  }

  .tableCol {
    width: calc(100% / 7);
    border-top: 1px dashed rgb(203, 201, 163);
    border-right: 1px dashed rgb(203, 201, 163)
  }

  .leftRightBtn {
    width: 10%;
    height: 100%;
  }

  .leftRightBtn:hover, .tableCol:hover {
    color: black;
    background: #FFCC38;
  }

  .checked {
    color: black;
    background: #FFCC38;
    cursor: pointer !important;
  }

  .checkBadge {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #52c41a;
    top: 0;
    right: 0;
    position: absolute
  }

  .topBorderNone {
    border-top: none !important;
  }

  .rightBorderNone {
    border-right: none !important;
  }
    /*布局部分*/
  .layout-side {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;

    justify-content: space-between;
    align-items: center;
  }

  .layout-center {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;

    justify-content: center;
    align-items: center;
  }

  .layout-center-top {
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;

    justify-content: flex-start;
    align-items: center;
  }

  .layout-left-top {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;

    justify-content: flex-start;
    align-items: flex-start;
  }

ps:width-100-per代表width:100%,有些没写出来的样式,就如class命名的语义一样,自己补充下

希望可以帮助到有需要的人,同时也是对之前完成的这个需求的总结,之后看一下可以让自己快速回想起来

你可能感兴趣的:(工作笔记)