基于 Dayjs 与 Vue2 的简易日历

/**
日历原始数据结构
months: [
['第1周', 1, 2, 3, 4, 5, 6, 7],
['第2周', 8, 9, 10, 11, 12, 13, 14],
['第3周', 15, 16, 17, 18, 19, 20, 21],
],
*/
<template>
  <div class="Calendar">
    <table class="width100p">
      <caption class="lineHeight30" style="color: #2c3e50">{{ formatDate(firstDay) }}</caption>
      <tbody>
        <tr class="tableClass border1cccccc">
          <th class="lineHeight30">教学周</th>
          <th class="lineHeight30">星期一</th>
          <th class="lineHeight30">星期二</th>
          <th class="lineHeight30">星期三</th>
          <th class="lineHeight30">星期四</th>
          <th class="lineHeight30">星期五</th>
          <th class="lineHeight30">星期六</th>
          <th class="lineHeight30">星期日</th>
        </tr>
        <template v-for="(week, index) in calendarData">
          <tr :key="'w'+index" class="tableClass border1cccccc">
            <td v-for="(atom, index) in week" :key="'d'+index">
              <div>{{ atom.label }}</div>

            </td>
          </tr>
        </template>
      </tbody>
    </table>
    <br>
    <button @click="doBeforeOneMonth">上一月</button>
    <button @click="doAfterOneMonth">下一月</button>
  </div>
</template>

<script>
import dayjs from 'dayjs'

export default {
  name: 'zydxCalendar', // 组件名称
  components: {},
  props: [], // 组件参数
  model: { // 用于 props 绑定父级 v-model
  },
  filters: { // 过滤器
  },
  computed: { // 计算属性
  },
  watch: { // 监听属性
  },
  data () {
    return {
      /*
      * 页面状态
      * */

      /*
      * 页面数据
      * */
      calendarData: [],
      firstDay: '2021-1-1'
    }
  },
  methods: {
    // 格式化时间
    formatDate (date) {
      return dayjs(date).format('YYYY年M月')
    },
    // 上一月
    doBeforeOneMonth () {
      this.firstDay = this.beforeOneMonth(this.firstDay)
      this.getCalendar(this.firstDay)
    },
    beforeOneMonth (date) {
      // date 格式 2021-1-1
      return dayjs(date).subtract(1, 'month').format('YYYY-M-D')
    },
    // 下一月
    doAfterOneMonth () {
      this.firstDay = this.afterOneMonth(this.firstDay)
      this.getCalendar(this.firstDay)
    },
    afterOneMonth (date) {
      // date 格式 2021-1-1
      return dayjs(date).add(1, 'month').format('YYYY-M-D')
    },
    // 渲染日历
    getCalendar (firstDay) {
      // firstDay 格式 2021-1-1
      const day = parseInt(dayjs(firstDay).format('D')) // 获取 日
      const yearMonth = dayjs(firstDay).format('YYYY-M')
      let firstDayOfWeek = dayjs(firstDay).day() // 当天是星期几
      const totalDays = dayjs(firstDay).daysInMonth() // 这个月一共有几天
      const remainDays = totalDays - day // 这个月还剩几天
      const days = [] // 当前月的所有号
      // 生成当月日期数组
      let i = -1
      while (i < remainDays) {
        days.push(day + i + 1)
        i++
      }
      // 月的数组
      let finalMonth = []
      let sliceStart = 0 // 截取日期的起始
      if (firstDayOfWeek === 0) {
        firstDayOfWeek = 7
      }
      let sliceGap = 7 - firstDayOfWeek + 1 // 截取几天
      let isArrayEmpty = false // 是否截取不出来了的标记
      let sliceTimes = 0
      while (!isArrayEmpty) {
        let weekTip = [] // 日历中每一条的数据
        if (sliceTimes === 0) { // 首次截取
          let weekTipAfter = days.slice(sliceStart, sliceGap)
          if (weekTipAfter.length < 7) {
            for (let i = 0; i < 7 - weekTipAfter.length; i++) { // 添加前面的空白
              weekTip.push('')
            }
          }
          weekTip = weekTip.concat(weekTipAfter)
        } else { // 再次截取
          weekTip = days.slice(sliceGap, sliceGap + 7)
          sliceGap = sliceGap + 7
          // 尾部添 空白
          let trailAppend = 7 - weekTip.length
          if (trailAppend < 7 && trailAppend > 0) {
            for (let j = 0; j < trailAppend; j++) {
              weekTip.push('')
            }
          }
          trailAppend = 0
        }
        sliceTimes++
        // 如果截取不出来了则 跳出循环
        if (weekTip.length !== 0) {
          finalMonth.push(weekTip)
        } else {
          isArrayEmpty = true
        }
      }

      // 添加教学周
      finalMonth.map((item, index) => {
        item.splice(0, 0, `第 ${index + 1} 周`)
      })

      // 更换数据结构
      let calendarData = []
      finalMonth.map((item) => {
        let calendarPart = []
        item.map((atom) => {
          if (typeof (atom) === 'number') {
            calendarPart.push({
              label: atom,
              date: yearMonth + '-' + atom,
              remarks: [] // 此处可以放一些数据
            })
          } else {
            calendarPart.push({
              label: atom
            })
          }
        })
        calendarData.push(calendarPart)
      })

      // 调试输出
      // console.log(day + '日当天是星期几', firstDayOfWeek)
      // console.log('这个月一共有几天: ', totalDays)
      // console.log('这个月还剩几天: ', remainDays)
      // console.log('days数组', days)
      // console.log('获得最终日历', finalMonth)
      // console.log('日历数据结构调整', calendarData)
      // 结束
      this.calendarData = calendarData
    }
  },
  beforeCreate () { // 播放加载动画
  },
  created () { // 结束加载动画, 发起异步请求
  },
  mounted () { // DOM构建完成, 即将显示页面
    this.getCalendar(this.firstDay)
  },
  updated () { // view重新渲染, 数据更新
  },
  beforeDestroy () { // 组件实例销毁之前
  }
}
</script>

<style scoped>
.lineHeight30 {
  line-height: 30px;
}
caption {
  padding: 0 0 0 30px;
  border: 1px #cccccc solid;
  border-bottom: none;
}
.tableClass th {
  border: 1px #cccccc solid;
  font-size: 14px;
}
.tableClass td {
  border: 1px #cccccc solid;
  font-size: 14px;
}
</style>
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容