2022用日历来打开~

1,063 阅读1分钟

日历的js实现

根据指定的日期生成所在月份的日历数据,在前端展示上可能需要有上个月、下个月数据的填充。

截屏2022-01-10 上午10.26.11.png

  1. 填补上个月的日历数据 例如选取的一月份日历数据,该月份的第一天为周六,也就需要在周日到周五之间填补上个月的数据。 获取本月的第一天属于星期几:
  const first = new Date(date).setDate(1);
  let day = new Date(first).getDay();

first对应的值为时间戳的形式,为number类型。 day对应了本月第一天是星期几,星期对应数值为0~6,表示星期天到星期六。

填补上个月空缺值:

  while(day > 0) {
    // TODO 构造单个的日期项,加入总的日期列表
    
    // Example
    const dayItem = {};
    dayList.push(dayItem);
    
    day--;
  }
  1. 填充本月的数据 由于每个月份的天数不一致,28~31天不等,所以选取最大值31天进行循环遍历。使用setDate来改变天数,若数据越界会自动改变设置日期所属的月份。
  const cur = new Date(date);
  const dd = new Date(date);
  for(let i = 1; i <= 31; i++) {
    dd.setDate(i);
    
    if (dd.getMonth() !== cur.getMonth()) {
      break;
    }
    
    dayList.push({
      daytime: new Date(dd).getTime(),
      // TODO 自行定义日期项所需要的参数
    });
  }

dd的值会随着setDate而改变,需要保留初始的日期数据。

  1. 填充下个月的数据
  // 获取本月的最后一天,也可以用其他方式获取
  const last = new Date(dayList[dayList.length -1].daytime);
  
  for(let i = 0; i < 6 - last.getDay(); i++) {
    // TODO 构造单个的日期项,加入总的日期列表
    
    // Example
    const dayItem = {};
    dayList.push(dayItem);
  }

完整代码:

日历逻辑数据同时配合日历组件样式使用,可以更具需要自行定义style中的参数。在数据构造中,非本月的数据都是用了值0来填充,可以根据实际需要设置该值。

/* 构造指定日期对应月份的日历数据 */
function constructMonthData(date: Date, isPure = true) {
  const dd = new Date(date);
  // 获取当前日期
  const now = new Date(dd);

  // 月份数据列表
  const dayList: DayItem[] = [];

  // 本月的第一天
  const firstDate = new Date(dd).setDate(1);
  // 本月第一天对应的星期
  let getDay = new Date(firstDate).getDay();

  // 填补当前日历上个月的空缺项
  while (getDay > 0) {
    const dayItem = {
      daytime: 0,
      isCurrentMonth: false,
      style: {},
    };

    dayList.push(dayItem);
    getDay--;
  }

  // 填补本月数据
  for (let i = 1; i <= 31; i++) {
    dd.setDate(i);

    if (dd.getMonth() !== now.getMonth()) {
      break;
    }

    dayList.push({
      daytime: new Date(dd).getTime(),
      isCurrentMonth: true,
      style: {},
    });
  }

  // 填充下个月的空缺项
  const lastDay = new Date(dayList[dayList.length - 1].daytime);
  for (let i = 0; i < 6 - lastDay.getDay(); i++) {
    const dayItem = {
      daytime: 0,
      isCurrentMonth: false,
      style: {},
    };

    dayList.push(dayItem);
  }

  // 返回本月的数据
  if (isPure) {
    return dayList.filter((day) => day.isCurrentMonth);
  }

  return dayList;
}

补充:使用真实日期值填充上下个月的占位数据

填充上个月的数据:

  let getDay = new Date(firstDate).getDay();
  while (getDay > 0) {
    const dayItem = {
      daytime: new Date(firstDate).setDate(0 - getDay + 1),
      isCurrentMonth: false,
      style: {},
    };

    dayList.push(dayItem);
    getDay--;
  }

Date.prototype.setDate(0)会被设置为上个月的最后一天,以此类推填补上个月和下个月的日期;

填充下个月的数据:

const lastDay = new Date(dayList[dayList.length - 1].daytime);
  for (let i = 0; i < 6 - lastDay.getDay(); i++) {
    const dayItem = {
      daytime: new Date(lastDate).setDate(lastDate.getDate() + i + 1),
      isCurrentMonth: false,
      style: {},
    };

    dayList.push(dayItem);
  }