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万年日历内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue循环中多个input绑定指定v-model实例

    Vue循环中多个input绑定指定v-model实例

    这篇文章主要介绍了Vue循环中多个input绑定指定v-model实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • 超简单的Vue.js环境搭建教程

    超简单的Vue.js环境搭建教程

    这篇文章主要为大家分享了一份超简单的Vue.js环境搭建教程,帮助大家快速搭建vue环境,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • Vue路由切换的两种方式示例详解

    Vue路由切换的两种方式示例详解

    这篇文章主要介绍了Vue路由切换的两种方式,主要包括标签切换和js切换,本文结合示例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • 解决vue中虚拟dom,无法实时更新的问题

    解决vue中虚拟dom,无法实时更新的问题

    今天小编就为大家分享一篇解决vue中虚拟dom,无法实时更新的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vuex入门最详细整理

    vuex入门最详细整理

    在本篇文章里小编给大家分享的是关于vuex入门最详细整理的相关内容,需要的朋友们参考下。
    2020-03-03
  • element滚动条组件el-scrollbar的使用详解

    element滚动条组件el-scrollbar的使用详解

    本文主要介绍了element滚动条组件el-scrollbar的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • vue项目打包之开发环境和部署环境的实现

    vue项目打包之开发环境和部署环境的实现

    这篇文章主要介绍了vue项目打包之开发环境和部署环境的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Vue如何实现u-form多个form表单同时校验

    Vue如何实现u-form多个form表单同时校验

    在 Vue 项目中使用 UView UI 的 u-form 组件时,多个表单同时校验的需求非常常见,本文主要介绍了如何使用 u-form 组件实现多个表单同时校验,需要的可以参考一下
    2025-01-01
  • vue实现列表的添加点击

    vue实现列表的添加点击

    这篇文章主要为大家详细介绍了vue实现列表的添加点击,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • Vue中xlsx的使用方法指南

    Vue中xlsx的使用方法指南

    这篇文章主要给大家介绍了关于Vue中xlsx的使用方法指南,有很多办法都可以实现,其中最简单的还是使用插件xlsx,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2023-07-07

最新评论