用 dayjs 得到一个日历的数据

需求

为了写一个自定义的日历组件,所以需要生成一个日历数据

思路

dayjs 是一个便利的日期库,和 moment 的 API 一样,首先可以用它来获得一些基础的日历信息,那些我并不想自己来计算。

为了生成日历数据,要先得到一个日期 date,然后为了方便进行日期计算,所以将 date 先转换成 dayjs 的对象,这里传入的 date 已经是 dayjs 的对象

获得基础信息

function generateCalendar(date, options = {
  weekStartsOnMonday: true,
}) {
  // 最终所需的data
  const calendar = [];
  // 今天的日期
  const today = dayjs();
  // 传入日期的年份
  const year = date.year();
  // 传入日期的月份(0-11,所以要+1)
  const month = date.month() + 1;
  // 传入日期的那个月有多少天
  const daysInMonth = date.daysInMonth();
  // 传入日期的那个月的第一天
  const monthFirstDay = date.startOf("month");
  // 传入日期的那个月的最后一天
  const monthEndDay = date.endOf("month");
  // 周起始日是周一还是周日
  const weekStartDay = options.weekStartsOnMonday ? 1 : 0;
}

星期的起始

众所周知,日历可以配置星期起始于周一或者周日,所以在生成时要考虑到。dayjs 的.day()方法可以拿到该日期是星期几,值为0-6,0代表星期日,所以为了方便我自己理解,写一个获得.day()对应的周索引的函数,1是一周的第一天,7是一周的最后一天

function getWeekIndex(day, startDay) {
  return (day - startDay + 7) % 7 + 1
}

例如获得到了一个日期是星期三,周起始日是周日,那么 weekIndex 就是 4,代表在这一周星期三位于第四个位置

// 当前月份第一天在周中是第几天
const monthFirstDayWeekIndex = getWeekIndex(monthFirstDay.day(), weekStartDay);
// 当前月份最后一天在周中是第几天
const monthEndDayWeekIndex = getWeekIndex(monthEndDay.day(), weekStartDay);

生成前一个月的数据

有了上面的基本信息,就可以开始生成日历数据了

首先是生成前一个月的数据,当月份第一天并非一周的开始日时,就会有上个月的日期数据

// 上个月的数据
const prevMonthDays = [];
if (monthFirstDayWeekIndex !== 1) {
  // 将这个月第一天减去1天,就拿到了上个月最后一天
  let prevMonthLastDate = monthFirstDay.subtract(1, 'day').date();
  const prevMonthYear = date.subtract(1, 'month').year();
  const prevMonthMonth = date.subtract(1, 'month').month() + 1;
  // 根据当前月份第一天在第几位,计算上个月份的天数
  for (let prevMonthWeekIndex = monthFirstDayWeekIndex - 1; prevMonthWeekIndex > 0; prevMonthWeekIndex--) {
    prevMonthDays.push({
      year: prevMonthYear,
      month: prevMonthMonth,
      date: prevMonthLastDate,
      day: getWeekDay(prevMonthWeekIndex, weekStartDay),
      isCurrentMonth: false,
      isPrevMonth: true,
      fullDate: `${prevMonthYear}-${padDate(prevMonthMonth)}-${padDate(prevMonthLastDate)}`
    });
    prevMonthLastDate--;
  }
  prevMonthDays.reverse();
}

假设这个月第一天是第一周的第三天,代表有两天的上个月的数据,所以在计算上个月数据时,是倒着添加进数组中的,所以在全部添加完毕后,需要将数组倒转

此处有两个函数,一个是getWeekDay,作用是根据周索引和周起始日来获取这一天是周几

const daysOfWeek = [7, 1, 2, 3, 4, 5, 6];
function getWeekDay(index, startDay) {
  return daysOfWeek[startDay + index - 1];
}

第二个是padDate,很简单就是为不足10的日期添加一个0

function padDate(date) {
  return String(date).padStart(2, '0');
}

生成下一个月的数据

因为日历数据中每周都有7天,所以会有当本月结束后,下个月的数据填补的情况

// 当前日历的周数
const calendarLength = Math.ceil((monthFirstDayWeekIndex - 1 + daysInMonth) / 7);
// 下个月的数据
const nextMonthDays = [];
// 当前日历去掉上月数据和当月数据的剩余天数
const nextMonthDaysLength = calendarLength * 7 - daysInMonth - prevMonthDays.length;
if (nextMonthDaysLength > 0) {
  const nextMonthYear = date.add(1, 'month').year();
  const nextMonthMonth = date.add(1, 'month').month() + 1;
  // 根据当前月份还剩下的天数,计算下个月份的天数
  for (let nextMonthDate = 1; nextMonthDate <= nextMonthDaysLength; nextMonthDate++) {
    nextMonthDays.push({
      year: nextMonthYear,
      month: nextMonthMonth,
      date: nextMonthDate,
      day: getWeekDay(monthEndDayWeekIndex + nextMonthDate, weekStartDay),
      isCurrentMonth: false,
      isNextMonth: true,
      fullDate: `${nextMonthYear}-${padDate(nextMonthMonth)}-${padDate(nextMonthDate)}`
    });
  }
}

生成日历数据

let currentMonthDate = 1;
for (let w = 1; w <= calendarLength; w++) {
  const week = [];
  // 在第一周时将上个月的数据添加进来
  if (w === 1) {
    week.push(...prevMonthDays);
  }
  for (let wi = week.length + 1; wi <= 7; wi++) {
    // 本月数据全部生成后就可以停止了
    if (currentMonthDate > daysInMonth) {
      break;
    }
    const day = {
      year,
      month,
      date: currentMonthDate,
      day: getWeekDay(wi, weekStartDay),
      isCurrentMonth: true,
      fullDate: `${year}-${padDate(month)}-${padDate(currentMonthDate)}`,
    }
    day.isToday = today.isSame(day.fullDate, 'day')
    week.push(day);
    currentMonthDate++;
  }
  calendar.push(week);
}
// 将下个月的数据添加进最后一周
calendar[calendar.length - 1].push(...nextMonthDays);

这样,日历的数据就全部得到了

原文链接:https://juejin.cn/post/7353877562303086629 作者:Lix

(0)
上一篇 2024年4月5日 下午4:51
下一篇 2024年4月5日 下午5:02

相关推荐

发表回复

登录后才能评论