React实现自定义日历

实现效果

在这里插入图片描述

特殊需求

  • 只需要展示星期一到星期五

依赖组件

完整代码

  • 主要是注意initDate()方法中的逻辑
import React, {useState, useEffect} from 'react';
import {Icon} from 'antd-mobile';
import styles from './index.less';

import moment from 'moment';
import {useSelector} from "dva";

moment.locale('zh-cn');

const dateFormatStr = 'YYYY-MM-DD';
const monthFormatterStr = 'YYYY年MM月';

const week = ['星期一', '星期二', '星期三', '星期四', '星期五']
const CustomCalendar = () => {
  const {rehydrated} = useSelector(state => state._persist);
  const {everyDayList} = useSelector(state => state.lianLianYing);
  const [currentDate, setCurrentDate] = useState(moment());
  const [dayList, setDayList] = useState([]);
  const {loginStatus} = useSelector(state => state.global);

  useEffect(() => {
    if (!rehydrated || !loginStatus) return;
    // console.log('currentDate', currentDate);
    // console.log('currentDate.day()', currentDate.day());
    // console.log('currentDate.date()', currentDate.date());
    // console.log('currentDate.month()', currentDate.month());
    // console.log('currentDate.year()', currentDate.year());
    // console.log('当月第一天', getMonthFirstDate(currentDate).format(dateFormatStr));
    // console.log('当月第一天星期几', getMonthFirstDate(currentDate).day());
    let temp = getMonthFirstDate(currentDate).endOf('month');
    // console.log('当月最后一天', temp.format(dateFormatStr));
    // console.log('当月最后一天+1', temp.add(1, 'd').month());
    initDate();
  }, [currentDate, rehydrated, loginStatus, everyDayList]);

  //获取某月第一天
  const getMonthFirstDate = (date) => {
    return moment(date.year() + '-' + (date.month() + 1) + '-01', dateFormatStr);
  };

  const initDate = () => {
    let dateArr = [];
    //当月第一天
    let monthFirstDate = getMonthFirstDate(currentDate);
    while (monthFirstDate.day() === 0 || monthFirstDate.day() === 6) {
      //当月第一天为周六或周日,重新获取当月第一天,向后顺延
      monthFirstDate.add(1, 'd');
    }
    // console.log('重新获取的当月第一天', monthFirstDate.format(dateFormatStr));
    //计算上个月需要并入的天数,也就是日历开头几天
    let preMonthDate = moment(monthFirstDate).subtract(1, 'M').endOf('month');
    // console.log('上月最后一天', preMonthDate.format(dateFormatStr));
    while (preMonthDate.day() !== 0 && preMonthDate.day() !== 6 && preMonthDate.day() !== 5) {
      let date = {
        date: '',
        day: preMonthDate.day(),
      }
      dateArr.push(date);
      preMonthDate.subtract(1, 'd');
    }
    while (monthFirstDate.month() === currentDate.month()) {
      //过滤周末
      if (monthFirstDate.day() !== 0 && monthFirstDate.day() !== 6) {
        const dayVal = everyDayList.find((val) => val?.init_date === monthFirstDate.format('YYYYMMDD'));
        let date = {
          date: monthFirstDate.date(),
          day: monthFirstDate.day(),
          total: dayVal?.total
        }
        dateArr.push(date);
      }
      monthFirstDate.add(1, 'd');
    }
    // console.log('dateArr', dateArr);
    setDayList(dateArr);
  };

  const preMonth = () => {
    const newDate = moment(currentDate).subtract(1, 'M');
    setCurrentDate(newDate)
  };

  const nextMonth = () => {
    const newDate = moment(currentDate).add(1, 'M');
    setCurrentDate(newDate)
  };

  return <div className={styles.wrap}>
    <div className={styles.title}>
      <div onClick={preMonth} className={styles.btn}><Icon type={'left'}/></div>
      <div>{currentDate.format(monthFormatterStr)}</div>
      {currentDate.isBefore(moment(), 'month') ?
        <div onClick={nextMonth} className={styles.btn}><Icon type={'right'}/></div> : <div className={styles.btn}/>}
    </div>
    <div className={styles.week}>
      {week.map((item, index) => {
        return <div className={styles.weekText} key={index}>{item}</div>
      })}
    </div>
    <div className={styles.days}>
      {dayList.map((item, index) => {
        return <div className={styles.day} key={index}>
          <div className={styles.date}>{item?.date}</div>
          {item?.date ?
            (item?.total ? (
              <div className={item?.total > 0 ? styles.red : styles.green}>{item?.total}</div>
            ) : <div className={styles.grey}>--</div>)
            : <div/>}
        </div>
      })}
    </div>
  </div>;
};
export default CustomCalendar;

  • less:
  • 忽略@rem,在父文件中定义
@import (reference) '../../styles/index.less';

.wrap {
  padding: 5*@rem;

  .title {
    display: flex;
    justify-content: center;
    align-items: center;
    padding-bottom: 10*@rem;

    .btn{
      width: 50*@rem;
    }

    & > div {
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 20*@rem;
    }
  }

  .week {
    display: flex;
    justify-content: space-around;

    .weekText {
      text-align: right;
      flex: 20%;
      padding-right: 10*@rem;
    }
  }

  .days {
    display: flex;
    justify-content: flex-start;
    flex-wrap: wrap;

    .day {
      width: 20%;
      padding-right: 5*@rem;
      border-top: solid @greyBorder 0.1px;
      padding-bottom: 5*@rem;
      padding-top: 5*@rem;
      color: white;

      .date {
        height: 30*@rem;
        display: flex;
        justify-content: flex-end;
        align-items: flex-end;
        font-size: 16*@rem;
        color: black;
        padding-right: 5*@rem;
      }

      .red {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        width: 100%;
        background: #FF6764;
        border-radius: 2*@rem;
        padding-right: 5*@rem;
        font-size: 14*@rem;

      }

      .green {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        background: #91C874;
        border-radius: 2*@rem;
        width: 100%;
        padding-right: 5*@rem;
        font-size: 14*@rem;
      }

      .grey {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        background: #e1e4ea;
        border-radius: 2*@rem;
        width: 100%;
        padding-right: 5*@rem;
        font-size: 14*@rem;
      }
    }
  }

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值