Vue实现万年日历的示例详解

 更新时间:2023年01月12日 08:53:48   作者:qb  
又是一个老生常谈的功能,接下来会从零实现一个万年日历,从布局到逻辑,再到随处可见的打卡功能。文中的示例代码简洁易懂,需要的可以参考一下

前言

又是一个老生常谈的功能,接下来会从零实现一个万年日历,从布局到逻辑,再到随处可见的打卡功能。涉及的内容有:

  • 日历的布局
  • 日期数据的产生
  • 年月的变化
  • 连续最长打卡日期
  • 补卡逻辑

1.日历的布局

<template>
  <div class="calendar">
    <!-- 年份和日期变化 -->
    <div class="select">
      <span class="select-icon select-sub" @click="changeYear(-1)">《</span>
      <span class="select-icon select-sub select-month" @click="changeMonth(-1)"><</span>
      <span>{{ currentMonth }}</span>
      <span class="select-icon select-add select-month" @click="changeMonth(+1)">></span>
      <span class="select-icon select-add" @click="changeYear(+1)">》</span>
    </div>
    <!-- 日历标题 -->
    <ul class="calendar-header">
      <li v-for="(item, index) in headerData" :key="index" class="calendar-header-item">
        <span>{{ item }}</span>
      </li>
    </ul>
    <!-- 日期内容 -->
    <div class="calendar-box">
      <div class="calendar-box-item" :class="{ delMark: !hasRemarkDays.includes(item) }" v-for="(item, index) in baseDateList" :key="index">
        <!-- 最高层级显示圆形日期 -->
        <div class="item-wrap" :class="{ hasMarked: hasRemarkDays.includes(item) }" @click="toRemark(item, currentDate)">
          <span class="item-date">{{ item ? item : "" }}</span>
          <span class="item-patch" v-if="isShowPatch && !hasRemarkDays.includes(item) && item && item < currentDate">补卡</span>
          <span class="item-current" v-if="currentDate == item"><i></i></span>
          <span class="item-continue" v-if="continueMarkObj.maxDay == item">连续{{ continueMarkObj.maxLen }}天</span>
        </div>
        <!-- 全遮罩背景淡橙色背景 -->
        <span class="all-mark" v-if="hasRemarkDays.includes(item)"></span>
        <!-- 左右遮罩,如果左边无打卡,遮住;如果右边无打卡,遮住 -->
        <span class="left-mark" v-if="index % 7 === 0 || !hasRemarkDays.includes(item - 1)"></span>
        <span class="right-mark" v-if="index % 7 === 6 || !hasRemarkDays.includes(item + 1)"></span>
      </div>
    </div>
  </div>
</template>

2.日期数据的产生

  computed: {
    // 返回当前的实际天数,从周一算起
    baseDateList() {
      let date = new Date(this.currentMonth);
      let monthFlag = date.getMonth() + 1;
      let yearFlag = date.getFullYear();
      let currentData = date.getDay();
      let dayLength = new Date(yearFlag, monthFlag, 0).getDate();

      // 周一之前的补0
      let dateBaseData = [];
      for (let i = 0; i < currentData; i++) {
        dateBaseData.push(0);
      }
      // 周一之后的实际填写
      for (let i = 0; i < dayLength; i++) {
        dateBaseData.push(i + 1);
      }

      return dateBaseData;
    },
  }

其中currentData表示今天是周几,在此之前的数组都补充为0,dayLength表示这月共多少天,然后,全部push进日期数据中。通过flex布局中的flex-wrap: wrap;让其自动换行即可。

3.年月的变化

// 修改年:当type = +1时,表示加一年,为-1时反之
changeYear(type) {
  let time = new Date(this.currentMonth);
  let year = time.getFullYear() + type;
  let month = time.getMonth() + 1;
  this.currentMonth = `${year}-${month}`;
},
// 修改月:当type = -1时,表示加一月,为-1时次之
changeMonth(type) {
  let time = new Date(this.currentMonth);
  let year = time.getFullYear();
  let month = time.getMonth() + 1;
  if (month === 12 && type > 0) { // 12月,并且是加的情况,年加1,月变为1
    year++
    month = 1
  } else if(month === 1 && type < 0) { // 1月,并且是减的情况,年减1,月变为12
    year--
    month = 12
  } else { // 其他情况,直接变化变量type的大小
    month += type
  }
  this.currentMonth = `${year}-${month}`;
},

引入type,既是加减的标志位,又是变量的大小。

4.连续最长打卡日期

getMaxDay() {
  let arr = this.hasRemarkDays;
  let buffChild = [];
  let max = [];
  
  for (let i = 0; i < arr.length; i++) {
    // 如果子集不连续了,重新进行赋值和更新
    if (buffChild.length && arr[i] - buffChild[buffChild.length - 1] > 1) {
      max = max.length > buffChild.length ? [...max] : [...buffChild];
      buffChild = [];
      buffChild.push(arr[i]);
      continue;
    }
    // 如果不是,直接进行累计
    buffChild.push(arr[i]);
  }
  return max.length > buffChild.length ? [...max] : [...buffChild];
},

假设max是最大的数组,那么,每次找到连续的数组都max进行对比并更新。在节点中,通过:class="{ hasMarked: hasRemarkDays.includes(item) }"的方式,为其添加hasMarked的样式。

5.补卡日期

补卡逻辑很简单,当前日期之前的日期,均可进行补卡,然后,在触发的方法中,通过$emit的方式向父组件传递需要补卡的日期,并触发补卡逻辑。

总结:日历的实现主要是应用JavaScript中Date对象的api和经典的flex布局,而最长连续打卡是常规算法最长连续子序列的实现方式之一。

到此这篇关于Vue实现万年日历的示例详解的文章就介绍到这了,更多相关Vue万年日历内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vite vue3多页面入口打包以及部署踩坑实战

    Vite vue3多页面入口打包以及部署踩坑实战

    因为我们公司的项目是多页面应用,不同于传统单页面应用,一个包就可以了,下面这篇文章主要给大家介绍了关于Vite vue3多页面入口打包以及部署踩坑的相关资料,需要的朋友可以参考下
    2022-05-05
  • Vue的computed计算属性你了解吗

    Vue的computed计算属性你了解吗

    这篇文章主要为大家详细介绍了Vue的computed计算属性,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • Vue中使用计算属性的知识点总结

    Vue中使用计算属性的知识点总结

    在本篇文章里小编给大家整理了一篇关于Vue中使用计算属性的知识点总结内容,对此有兴趣的朋友们可以跟着学习参考下。
    2021-12-12
  • vue-router懒加载速度缓慢问题及解决方法

    vue-router懒加载速度缓慢问题及解决方法

    这篇文章主要介绍了vue-router懒加载速度缓慢问题及解决方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • Vue+OpenLayer为地图添加风场效果

    Vue+OpenLayer为地图添加风场效果

    这篇文章主要为大家展示了一个demo,即利用Vue和OpenLayer在地图上面添加风场效果,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-04-04
  • 安装多版本Vue-CLI的实现方法

    安装多版本Vue-CLI的实现方法

    这篇文章主要介绍了安装多版本Vue-CLI的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 关于elementUI select控件绑定多个值(对象)

    关于elementUI select控件绑定多个值(对象)

    这篇文章主要介绍了关于elementUI select控件绑定多个值(对象),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • vue使用xlsx导入到表格中示例代码

    vue使用xlsx导入到表格中示例代码

    这篇文章主要介绍了vue使用xlsx导入到表格中代码,具体实现是先通过FileReader将上传的文件读取为二进制数据,然后使用xlsx将它解析成JSON数据,最后将JSON数据填充到表格中,需要的朋友可以参考下
    2023-11-11
  • vue3时间插件之Moment.js使用教程

    vue3时间插件之Moment.js使用教程

    这篇文章主要给大家介绍了关于vue3时间插件之Moment.js使用的相关资料,需要的朋友可以参考下
    2023-09-09
  • vue部署后静态文件加载404的解决

    vue部署后静态文件加载404的解决

    这篇文章主要介绍了vue部署后静态文件加载404的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04

最新评论