React 实现自定义日历

项目中又遇到了自定义日历,记录下来,方便以后抄代码~~0_0~

自定义日历最重要的三步:

  1. 找到当前月有多少天,以及第一天是星期几--灰常重要!
  2. 根据第一步找到需要填充的上月的日期,因为第一步中获取的到下标刚好是需要显示的上个月的天数
  3. 根据第一步,第二步获取需要填充的下个月的日期

这里是基于moment实现的~

先介绍几个moment方法:

一 :moment.weekdaysMin()

获取缩写的星期

React 实现自定义日历

二: moment().daysInMonth()

获取当前月的天数

React 实现自定义日历

三: moment().startOf('month').weekday()

获取当前月第一天是星期几

React 实现自定义日历

 四: moment().subtract(1, 'month')

获取上个月月份

React 实现自定义日历

 

 四: moment().add(1, 'month')

获取下个月月份

React 实现自定义日历

 上代码:

index.jsx

import React, { useState } from 'react';
import classnames from 'classnames';
import { initCalendar } from '../utils';
import { Typography } from 'antd';
import Header from '../header';

import './index.less';

export default function Content({ className }) {
  const [days, setDays] = useState(initCalendar());
  const [active, setActive] = useState(0);

  return (
    <div className={classnames('content_container', className)}>
      <div className={classnames('toolbar_container', className)}>
        <Space>
          <Button icon={<LeftOutlined />} type="text" onClick={handleUp} />
          {currentMonth.format(YEAER_MONTH_FORMAT_ZH)}
          <Button icon={<RightOutlined />} type="text" onClick={handleDown} />
        </Space>
      </div>
      <div className="content_wrapper">
        {days?.map((day, index) => (
          <div
            onClick={() => setActive(index)}
            className={classnames('day_container', {
              active: index === active,
            })}
            key={index}
          >
            <Typography.Text>{day}</Typography.Text>
          </div>
        ))}
      </div>
    </div>
  );
}

index.less

.content_container {
  width: 100%;
  height: 100%;
  .toolbar_container {
    display: flex;
    justify-content: center;
    border: 1px solid rgb(215 215 215);
    background: white;
  }
  .calendar_content_wrapper {
    width: 100%;
    height: 100%;
    display: grid;
    border: 1px solid rgb(215 215 215);
    grid-template-columns: repeat(7, 1fr);
    background: white;
    .day_container {
      display: flex;
      justify-content: center;
      height: 100px;
      box-sizing: content-box;
      border-right: 1px solid rgb(215 215 215);
      border-bottom: 1px solid rgb(215 215 215);
      cursor: pointer;
      position: relative;
      .more {
        position: relative;
        width: 23px;
        height: 23px;
        border: 1px solid #000;
        left: 0;
        bottom: 0;
      }
    }

    .date_title {
      display: inline-block;
      width: 24px;
      height: 20px;
      line-height: 20px;
      margin-left: 4px;
      text-align: center;
      font-size: 16px;
      font-family: PingFangSC-Regular, PingFang SC;
      font-weight: 400;
      color: rgb(103 113 122);
    }
    .active {
      box-shadow: inset 0px 0px 5px 1px lightgreen;
    }
    .isToday {
      background: lightgreen;
    }
  }
}

utils.js

import moment from 'moment';
import { YEAER_MONTH_FORMAT, INIT_DAYS } from './const';
/**
 * 获取当前月的天数
 */
console.log(moment().format('YYYY-MM-DD'), 'moment()');
export function getMonthDays() {
  return moment().daysInMonth();
}

/**
 * 获取当前月第一天是星期几
 */
export function getWeekDays() {
  return moment().startOf('month').weekday();
}

/**
 * 获取上个月份
 */
export function getLastMonth() {
  return moment().subtract(1, 'month').format(YEAER_MONTH_FORMAT);
}

/**
 * 获取下个月份
 */
export function getNextMonth() {
  return moment().add(1, 'month').format(YEAER_MONTH_FORMAT);
}

/**
 * 初始化日历
 */
export function initCalendar() {
  // 当前月天数
  const totalDaysInMonth = getMonthDays();
  // 上个月天数
  let totalDaysInLastMonth = getMonthDays(getLastMonth());
  // 下个月开始日期
  let nextFirstDate = 1;

  const lastDays = [],
    currentDays = [],
    nextDays = [];

  // 当前月第一天是星期几(索引值)
  /**
   * 这里的索引值刚刚好是需要填充的上月的天数
   */
  const currentWeekDay = getWeekDays();

  for (let i = 0, len = 42; i < len; i++) {
    // 填充上个月的天数
    if (i < currentWeekDay) {
      lastDays.push(totalDaysInLastMonth);
      totalDaysInLastMonth--;
    }
    // 填充下个月的天数
    else if (i >= totalDaysInMonth + currentWeekDay) {
      nextDays.push(nextFirstDate);
      nextFirstDate++;
    }
    // 填充当前月天数
    else {
      currentDays.push(i - currentWeekDay + 1);
    }
  }
  // 上个月需要倒序显示
  return [...lastDays.reverse(), ...currentDays, ...nextDays];
}

const.js

import moment from 'moment';

export const YEAER_MONTH_FORMAT_ZH = 'YYYY年MM月';
export const YEAER_MONTH_FORMAT_EN = 'YYYY-MM';
export const YEAER_MONTH_FORMAT_FULL = 'YYYY-MM-DD';
// 获取星期
const [_, ...rest] = moment.weekdaysMin();

// 将星期天放置数组最后
export const WEEk_HEADER = [...rest, _];

// 日历布局为6 * 7单元格
export const TOTAL_LENGTH = 6 * 7;

// 初始化一下下
export const INIT_DAYS = Array(TOTAL_LENGTH)
  .fill(0)
  .map((_, index) => +index + 1);

上一篇:聊聊React中的受控组件与非受控组件——个人理解


下一篇:React的路由跳转