手撕周日历插件

239 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

前言

上一段时间需要做一个包含周报功能的,大致效果如下图所示:

1659877025659.png

一开始的打算是寻找一个开源插件的,但是经过一段时间的调研发现,没有十分契合的插件,要么是满足功能,但是ui调整起来比较费力;要么是ui很契合,但是功能与期望有差距。经过一段时间的挣扎与评估,最终决定自己手撕。

工具

插件库:dayjs 开发工具:vscode

之所以选用dayjs,完全是因为dayjs封装的很好,处理了日期的很多兼容性问题,而且体积不是很大。

核心逻辑

1. 计算当前月的第一周

获取当前月的第一天相对来说很简单,这里简单的介绍两种方式:

  • 获取当前时间的年+月,然后拼接上日期01即可;
    const day = dayjs();
    const year = day.year().toString();
    const month = (day.month() + 1).toString();
    
    // year+month+01
  • 借用dayjs提供的startOf方法
    dayjs().startOf('month')

获取了每个月的第一天了,但是并不意味着我们找到了每个月的第一个周。试想一下,如果这个月的第一天是星期二到星期日,这就意味着这个月的前几天(星期日之前)是上一个月的最后一个周;如果这个月的第一天是星期一,这就意味着这个月的第一天是这个月的第一个周的开始时间。

也就是说我们要判断一下,每个月的第一天是星期几,如果是星期一那么这个月的第一周的起始时间就是1号,否则那么下一个星期一才是这个这个月的第一周的开始时间。

我这里也是直接借用了dayjs来实现的:

    let day = dayjs(date).startOf('month').day(1);

    if (day.date() > 7) {
        day = day.add(1, 'week');
    }

特殊说明一下:dayjs获取的day(1)是当前时间所在周的星期一的日期,所以说如果大于7,说明是上个月的最后一个周,那么只需要在这个基础上加上7天,就是这个月的第一个周的星期一的日期了。

2. 生成日期列表

既然有了当前月的第一个月的开始时间,那么结束时间也就可以拿到了,只需要加6就可以了

    day.add(6, 'day');

既然有了第一个周,那么剩下的周只需要进行循环即可拿到了,但是循环的终止机制有啥怎么触发呢?如何确认时间是否是进入了下一个月了呢?

其实说起来很简单,只需要判断时间再次小于等于7即可,理解了这个之后,剩下的就很简单了,这里我就直接亮一下我的代码了:

    const weekList = [];

    let day = getFirstMondayOfMonth(date);

    do {
        const { start, end } = getIntervalDateOfWeek(day);

        weekList.push({ start, end });
        day = day.add(1, 'week');
    } while (day.date() > 7);

尾语

到这里一个周日历插件的逻辑就基本实现了,剩下的只需要进行一下简单的切换和ui的调整即可了。希望小编说的这个对大家的日常开发过程有所帮助,欢迎大家在下方进行留言交流。