日历前端📅渲染开发记录

需求分析

突然接到一个排班的需求。

看了下算是比较老的项目,使用的是vue2+element开发的,使用的是element的UI组件库。去查看下element的Calendar组件。⬇️长这样

看起来没什么大问题。星期几信息和每天的信息都很详细。但是和我的需求不符合,排班需要在一个日期范围内显示一些内容。显然element的calendar文档只能选中单个日期,无法完全满足我的需求。

手滑不小心点到了电脑的日历📅组件⬇️

于是就想着按照Apple 的日历应用UI来做。

代码逻辑分析

  • 使用table还是flex布局来渲染?
  • 当当前月份的第一天不是周日怎么办?
  • 当当前月份的最后一天不是周六怎么办?

代码实现

选择table来布局。根据table的布局来定数据结构

css 复制代码
 table
  thead
   th
  tbody
   tr
    td

优先渲染表头

由于项目内部已经安装了moment时间处理库,所以本文都使用moment时间处理库来做时间处理。当然你也可以用类似的dayjs来处理一样的。主要使用的是moment时间的加减方法,用到的方法如下。

  • fn.startOf
  • fn.endOf
  • fn.add
  • fn.subtract
  • fn.format
  • fn.day()

实现代码思路

  • 通过fn.startOf和fn.endOf来获取需要截取的开始结束时间区间。
  • 判断上一步的开始时间是星期几,结束时间是星期几。如果开始时间不是星期天或者最后一天不是星期六则需要补全上个月的日期和下个月的日期。因为我们是以7天为一个横向区间。

代码实现

日历头的数据渲染

css 复制代码
 const titles = {
     0: '周日',
     1: '周一',
     2: '周二',
     3: '周三',
     4: '周四',
     5: '周五',
     6: '周六',
 };
 let i = 0;
 while (i < 7) {
     this.calendarHeader.push({
         title: titles[i],
         value: i,
     });
     i++;
 }

显示区间的数据渲染

kotlin 复制代码
 const startDate = this.$moment(this.currentDate).startOf('month');
 const endDate = this.$moment(this.currentDate).endOf('month');
 let monthdays = [];
 for (let i = startDate; i <= endDate; i.add(1, 'day')) {
     monthdays.push({
         date: i,
         week: this.$moment(i).day(),
         format: i.format('YYYY/MM/DD'),
         day: i.format('DD'),
         data: {}
     });
 }

判断是否需要填充上个月的日期作为本月补充显示

ini 复制代码
 const startDay = monthdays[0];
 if (startDay.week !== 0) {
     // 填补上月在本周的日期
     const {format, week} = startDay;
     let frontDays = [];
     for (let i= week -1; i >= 0;i--) {
         const date = this.$moment(format).subtract( i, 'day');
         const subtractDay = this.$moment(format).subtract( i + 1, 'day');
         const day = {
             date,
             week: subtractDay.day(),
             format:  subtractDay.format('YYYY/MM/DD'),
             day: subtractDay.format('DD'),
             data: {
                 disabled: true
             }
         }
         frontDays.push(day);
     }
     monthdays = [...frontDays, ...monthdays]
 }

判断是否需要填充下个月的日期作为本月补充显示

css 复制代码
 const endDay = monthdays[monthdays.length - 1]
 if(endDay.week !== 6) {
     const {format, week} = endDay;
     let j = 1;
     for (let i = week;i < 6;i++) {
         monthdays.push({
             date: this.$moment(format).add( j, 'day'),
             week: week + j,
             format:  this.$moment(format).add( j, 'day').format('YYYY/MM/DD'),
             day: this.$moment(format).add( j, 'day').format('DD'),
             data: {
                 disabled: true
             }
         });
         j++
     }
 }

以0-6为区间判断一周做数据切割

ini 复制代码
 let _week = [];
 for (let i = 0; i < monthdays.length; i++) {
     const { week } = monthdays[i];
     if (week <= 6 && week !== 0) {
         _week.push(monthdays[i]);
         if (i === monthdays.length - 1) {
             // 如果这个月的最后几天没有星期天就把剩下的天数单独分为一周
             this.calendar.push(_week);
             _week = [];
         }
     } else if (week == 0) {
         this.calendar.push(_week);
         // 如果是周日则换一行
         _week = [];
         _week.push(monthdays[i]);
     }
 }

至此完成之后页面长这样

相关推荐
乔旭伟10 分钟前
Vben3 中后台表格封装实战:useVbenVxeGrid 的全局收敛与七个坑
前端·anti-design-vue·1024程序员节
鶴哥只手遮天19 分钟前
jQuery 4.0 源码架构与工程实践-第 10 章 尺寸、几何与显隐
前端·javascript·jquery
Mia_墨黎21 分钟前
2026 Windows 11 终端美化完全指南
前端·后端
用户18806874935239 分钟前
戴着 Rokid 接成语:用 AIUI 做一局有提示、有复盘的“接着说”
前端
Sakura_j_h_1 小时前
Three.js 单文件离线机械臂工作台:爆炸图、透明外壳与剖面
前端·机械臂·webgl·three.js·1024程序员节·esbuild
计算机魔术师2 小时前
管谷歌的不是Pichai一个人,是一整层AI智能体
前端
米米商聊2 小时前
图标能点,按钮就可用了吗?键盘、名称与收藏状态
前端·javascript
Younglina3 小时前
三个晚上,我和 WorkBuddy 做了个生图网站
前端·后端·ai编程
xy34533 小时前
Axure 9.0 内联框架加载方式
前端·ui·html·axure·原型·产品设计
漫天转悠4 小时前
Vue3白屏排查实录-Transition与多根模板
vue.js·1024程序员节