Bootstrap

vue 自定义月日历日程组件(MSchedule)

效果图

组件的使用 

  1. 日程内容可以自定义
  2. 状态对应颜色可以自定义
<MSchedule :scheduleList="plan" :isExpend="false" :hasNumExpend="3" @handleDetail="handleDetail" @chooseEntireCard="chooseEntireCard"
                   @changeMonth="changeMonth">
          <template v-slot:card="{row}">
            <span>时段:{{ row.timePeriod }}</span>
            <span>课程:{{ row.course }}</span>
          </template>
        </MSchedule>

下载组件 使用教程及参数点击这里

npm i mschedule -S

组件完整代码如下

html部分

<template>
  <div class="month-container">
    <div class="month-top">
      <div class="m-btn-wrap">
        <span @click="handleShowLastMonth">上一月</span>
        <span @click="handleShowToday"> 今天 </span>
        <span @click="handleShowNextMonth">下一月</span>
      </div>
      <span class="m-today-date"> {{ year }}年{{ month > 9 ? month : `0${month}` }}月</span>
      <div class="m-card-status">
        <div v-for="sta in cardStatus">
          <span class="square" :style="{background:sta.color}"></span>
          <span class="title">{{ sta.title }}</span>
        </div>
      </div>
    </div>
    <div class="m-date-wrap">
      <ul class="m-week">
        <li>日</li>
        <li>一</li>
        <li>二</li>
        <li>三</li>
        <li>四</li>
        <li>五</li>
        <li>六</li>
      </ul>
      <ul class="m-day">
        <li v-for="(item,index) in days"
            :class="{'m-isActive':item.isActive,'m-isCurToday':item.isCurToday}"
            :key="index">
          <span @click="handleChooseCard(item)" class="m-date" :class="{'m-isCurMonth':item.isNextMonth||item.isLastMonth}">
            {{ item.day }}
          </span>
          <template v-for="(plan,i) in item.planList">
            <div :key="`plan${i}`" @click="handleDetail(plan)"
                 class="m-card-default"
                 :style="{background: cardStatus[plan.status].color}">
              <slot name="card" :row="plan"></slot>
            </div>
          </template>
        </li>
      </ul>
    </div>
  </div>
</template>

js 部分  import MyTools from "../utils/MyTools"; 点击这里

<script>
import MyTools from "../utils/MyTools";

export default {
  name: 'monthSchedule',
  props: {
    list: {
      type: Array,
    },
    cardStatus: {
      type: Object,
      default: () => {
        return {
          1: {
            title: '已过期',
            color: '#9CADADB7'
          },
          2: {
            title: '进行中',
            color: '#FF6200'
          },
          3: {
            title: '未开始',
            color: '#3291F8'
          },
        }
      }
    }
  },
  data() {
    return {
      year: '',//年
      month: '',//月
      days: [],//日期
      endTime: null,
      startTime: null,
      monthValue: '',
    }
  },
  methods: {
    changeMonth() {
      const date = this.monthValue && this.monthValue.split('-').map(Number) || []
      if (date.length === 0) {
        return
      }
      this.year = date[0];
      this.month = date[1]
      this.days = [];
      this.pushDays();
    },
    //得到当前年这个月分有多少天
    getDays(Y, M) {
      return new Date(Y, M, 0).getDate();
    },
    //得到当前年,这个月的一号是周几
    getWeek(Y, M) {
      let now = new Date()
      now.setFullYear(this.year)
      now.setMonth(this.month - 1)
      now.setDate(1);
      return now.getDay();
    },
    /**
     * 获取本月日期
     */
    pushDays() {
      //将这个月多少天加入数组days
      for (let i = 1; i <= this.getDays(this.year, this.month); i++) {
        const _day = `${i > 9 ? i : '0' + i}`, _month = `${this.month > 9 ? this.month : '0' + this.month}`,
            date = `${this.year}-${_month}-${_day}`;
        this.days.push({
          day: _day,//
          date,
          planList: this.list.filter(item => item.date === date),
          isCurMonth: true,
          month: _month,
          year: `${this.year}`,
          timestamp: new Date(date).getTime(),//转换时间戳
        })
      }
      this.getLastMonthDays()
      this.getNextMonthDays()
    },
    /**
     * 获取下个月的日期
     */
    getNextMonthDays() {
      const month = this.month < 12 ? this.month + 1 : 1,
          year = this.month < 12 ? this.year : this.year + 1,
          len = 42 - this.getDays(this.year, this.month) - this.getWeek(this.year, this.month)
      //将下个月要显示的天数加入days
      for (let i = 1; i <= len; i++) {
        const _day = `${i > 9 ? i : '0' + i}`, _month = `${month > 9 ? month : '0' + month}`,
            date = `${year}-${_month}-${_day}`;
        this.days.push({
          day: _day,
          date,
          month: _month,
          year: `${year}`,
          planList: this.list.filter(item => item.date === date),
          isNextMonth: true,
          timestamp: new Date(date).getTime()
        })
      }
    },
    /**
     * 获取上个月的日期
     */
    getLastMonthDays() {
      const month = this.month > 1 ? this.month - 1 : this.year > 1970 ? 12 : 1,
          year = this.month > 1 ? this.year : this.year > 1970 ? this.year - 1 : 1970,
          len = this.getWeek(this.year, this.month),
          lastMonthDays = this.getDays(this.year, this.month - 1)
      //将上个月要显示的天数加入days
      for (let i = 0; i < len; i++) {
        const _month = month > 9 ? `${month}` : `0${month}`,
            date = `${year}-${_month}-${lastMonthDays - i}`;
        this.days.unshift({
          day: `${lastMonthDays - i}`,
          date,
          month: _month,
          year: `${year}`,
          planList: this.list.filter(item => item.date === date),
          isLastMonth: true,
          timestamp: new Date(date).getTime(),
        })
      }
    },
    /**
     * 获取日期数据
     */
    getDate() {
      let now = new Date();
      this.year = now.getFullYear();
      this.month = now.getMonth() + 1;
      this.pushDays();
    },
    /**
     * 下个月
     */
    handleShowNextMonth() {
      if (this.month < 12) {
        this.month = this.month + 1;
      } else {
        this.month = this.month = 1;
        this.year = this.year + 1;

css部分

<style>
ul {
  list-style: none;
}
.month-container {
  width: 100%;
  border: 1px solid #ddd;
  padding: 20px;
  box-sizing: border-box;
}

.month-top {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1% 0;
  box-sizing: border-box;

}

.month-top .m-btn-wrap {
  width: 200px;
  display: flex;
  justify-content: space-around;
  color: #409EFF;

}

.month-top .m-btn-wrap > span {
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 15px;

}

.month-top .m-card-status {
  display: flex;
  width: 20%;
  justify-content: flex-end;
}

.month-top .m-card-status > div {
  flex: 1;
  display: flex;
  padding: 0 2%;
  white-space: nowrap;
  line-height: 20px;
  box-sizing: border-box;

}

.month-top .m-card-status > div .square {
  display: flex;
  width: 16px;
  height: 16px;
  border-radius: 4px;
  box-sizing: border-box;
}

.month-top .m-card-status > div .title {
  display: flex;
  align-items: center;
  line-height: 16px;
  margin-left: 4px;
  font-size: 14px;
}

.m-date-wrap {
  width: 100%;
  height: auto;

}

.m-date-wrap .m-week {
  width: 100%;
  height: 80px;
  margin: 0;
  line-height: 80px;
  display: flex;
  flex-direction: row;
  font-size: 16px;
  background: #EAEDF2;
  box-sizing: border-box;

}

.m-date-wrap .m-week > li {
  width: 14.28%;
}

.m-date-wrap .m-day {
  width: 100%;
  display: flex;
  flex-direction: row;
  padding: 0;
  margin: 0;
  font-size: 14px;
  flex-wrap: wrap;
  box-sizing: border-box;

}

.m-day .m-date{
  cursor: pointer;
}

.m-date-wrap .m-day > li {
  width: 14.28%;
  padding: 1%;
  min-height: 100px;
  box-sizing: border-box;
  border: 1px solid #ddd;
}

.m-date-wrap .m-day > li .m-card-default {
  cursor: pointer;
  width: 100%;
  min-height: 60px;
  border-radius: 8px;
  display: flex;
  margin: 6% 0;
  flex-direction: column;
  justify-content: space-around;
  white-space: nowrap;
  color: #fff;
  background: #FF6200;
  padding: 2% 4%;
  box-sizing: border-box;
}

.m-date-wrap .m-day > li:nth-child(n+8) {
  border-top: none;
}

.m-date-wrap .m-day > li:nth-child(n+1) {
  border-right: none;
}

.m-date-wrap .m-day > li:nth-child(7n) {
  border-right: 1px solid #ddd
}

.m-isCurMonth {
  background: #fff;
  color: #c0c4cc;
}

.m-isCurToday {
  background: #FFF1F0 10000%;
  color: #FF2525;
}


.m-isActive {
  background: #409EFF;
  color: #f2f8fe;
}

</style>

;