2023-01-18 工作记录--React-手写日历+JS-计算某一日期对应一周的日期

【一】React-手写日历

一、实现效果 ⭐️

在这里插入图片描述

二、实现代码 ⭐️

1、封装手写的日历组件 🍓

calendar/index.jsx

'use strict';

import React from 'react';
import './index.less';

function Calendar(props) {
  // 从父页面传递过来的参数
  const {
    // 日历当前需展示的年【未传则展示当前年】
    year,
    // 日历当前需展示的月【未传则展示当前月】
    month,
  } = props;

  /**
   * 计算某一日期对应一周的日期(比如:getWeekDataList('2023-01-18'); 结果为:['1.16', '1.17', '1.18', '1.19', '1.20', '1.21', '1.22'])
   * @param {String} data 日期【格式: 年-月-日(xxxx-xx-xx)(比如:'2023-01-18')】
   * @returns 一个含周一到周日日期的数组
   */
  const getWeekDataList = (data) => {
    // 根据日期获取本周周一~周日的年-月-日
    const weekList = [];
    const date = new Date(data);
    // 判断本日期是否为周日,获取本周一日期
    if (date.getDay() === 0) {
      date.setDate(date.getDate() - 6);
    } else {
      date.setDate(date.getDate() - date.getDay() + 1);
    }
    const myMonth = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : '' + (date.getMonth() + 1); // 月
    const myDate = date.getDate() < 10 ? '0' + date.getDate() : '' + date.getDate(); // 日
    weekList.push(parseInt(myMonth) + '.' + parseInt(myDate));
    // 获取周二以后日期
    for (let i = 0; i < 6; i++) {
      date.setDate(date.getDate() + 1);
      const myMonth = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : '' + (date.getMonth() + 1); // 月
      const myDate = date.getDate() < 10 ? '0' + date.getDate() : '' + date.getDate(); // 日
      weekList.push(parseInt(myMonth) + '.' + parseInt(myDate));
    }
    // console.log('一个含周一到周日日期的数组', weekList);
    return weekList;
  };

  // 自定义参数
  const d = new Date(),
    curYear = d.getFullYear(), // 当前年
    curMonth = d.getMonth() + 1 < 9 ? '0' + (d.getMonth() + 1) : '' + (d.getMonth() + 1), // 当前月【字符串型】
    _curMonth = parseInt(curMonth), // 当前月【数值型】
    curDate = d.getDate() < 9 ? '0' + d.getDate() : '' + d.getDate(), // 当前日【字符串型】
    _curDate = parseInt(curDate), // 当前日【数值型】
    weekArr = ['日', '一', '二', '三', '四', '五', '六']; // 数组-星期

  // 渲染日历行内容
  const renderDays = (row) => {
    /** 签到状态处理【1: 状态-过去 未签到, 2: 状态-已签到, 3: 状态-将来 未签到】 */
    const statusMap = {
      // 状态-过去 未签到
      1: <p className="status status1"></p>,
      // 状态-已签到
      2: <p className="status status2"></p>,
      // 状态-将来 未签到
      3: <p className="status status3"><span>+2</span></p>,
    }

    /** 初始化年月日相关滴数据 */
    const currentYear = year || new Date().getFullYear(), // 父页面传过来的年 || 当前年【静态值】
      currentMonth = month || new Date().getMonth() + 1, // 父页面传过来的月 || 当前月【静态值】
      _month = currentMonth, // 动态值 等于_month,做加1、减1处理
      days = new Date(currentYear, currentMonth, 0).getDate(), // 获取某年月对应的天数
      idx = new Date(`${currentYear}/${currentMonth}/01`).getDay(), // 获取某年月第一天对应的星期(0-6)【注意:这里需要用'/'进行分割,避免ios兼容问题(ios的Date对象不支持 yyyy-MM-dd 的格式)】
      nextIdx = new Date(`${currentYear}/${currentMonth}/${days}`).getDay(); // 获取某年月最后一天对应的星期(0-6)【注意:这里需要用'/'进行分割,避免ios兼容问题(ios的Date对象不支持 yyyy-MM-dd 的格式)】
    console.log('父页面传过来的年 || 当前年', currentYear);
    console.log('父页面传过来的月 || 当前月', currentMonth);
    console.log('某年月对应的天数', days);
    console.log('某年月第一天对应的星期(0-6)', idx);
    console.log('某年月最后一天对应的星期(0-6)', nextIdx);

    /** 【重要】日期数组数据处理 */
    const dateArr = new Array(42).fill(0); // 自定义一个数据为0的42位数组

    let lastMonth = undefined; // 上一个月月份
    let nextMonth = undefined; // 下一个月月份
    /** 1、处理上一个月月份 */
    if (currentMonth == 1) {
      lastMonth = 12;
    } else {
      lastMonth = _month - 1;
    }
    console.log('上一个月月份', lastMonth);
    /** 2、处理下一个月月份 */
    if (currentMonth == 12) {
      nextMonth = 1;
    } else {
      nextMonth = _month + 1;
    }
    console.log('下一个月月份', nextMonth);
    /** 3、获取到上一个月对应的天数 */
    const lastMonthDays = new Date(currentYear, lastMonth, 0).getDate();
    console.log('上一个月对应的天数', lastMonthDays);
    /** 4、上一个月补位展示处理 */
    const lastSteps = idx; // 向前补好多位
    for (let i = 0; i <= lastSteps; i++) {
      const lastDay = lastMonthDays - idx + i + 1; // 上一个月补位对应的日
      dateArr[i] = `${lastMonth}.${lastDay}`; // 月.日(上一个月)
    }
    /** 5、当前月份展示处理 */
    for (let i = 0; i < days; i++) {
      const currentDay = i + 1; // 当前月份对应的日
      dateArr[lastSteps + i] = `${currentMonth}.${currentDay}`; // 月.日(当前月)
    }
    /** 6、下一个月补位展示处理 */
    const nextSteps = 6 - nextIdx; // 向后补好多位
    for (let i = 0; i < nextSteps; i++) {
      const nextDay = i + 1; // 下一个月补位对应的日
      dateArr[days + lastSteps + i] = `${nextMonth}.${nextDay}`; // 月.日(下一个月)
    }
    console.log('日期数组数据', dateArr);
    // [...weekArr, ...dateArr]表示涵盖了第一行的日期,若不需要日期,则使用dateArr
    const rowDateArr = [...weekArr, ...dateArr].slice(row * 7, row * 7 + 7); // 获取到对应行的行数组数据
    console.log('行数组数据', rowDateArr);

    /** 渲染行数据 */
    return rowDateArr?.map((item, i) => {
      console.log('item', item);

      if (item === 0) {
        // 为0时,则返回一个空标签,不继续后续操作
        return <div key={i}></div>;
      }

      // 是否是 日期内容(true -> 不是星期内容,false -> 是星期内容)
      const isNotWeek = weekArr.indexOf(item) === -1;
      // 是否是 今年
      const isCurrentYear = currentYear === curYear;
      // 是否是 今月
      const isCurrentMonth = item?.split('.')[0] * 1 === _curMonth;
      // 是否是 今日
      const isCurrentDay = item?.split('.')[1] * 1 === _curDate;
      // 是否是 当前月份/父页面传过来的月份的日期(数据不为0 && 不是星期内容 && 是当前月份/父页面传过来的月份)
      const isCurrentDate = isNotWeek && isCurrentMonth;
      // 是否是 今年今月今日
      const isToday = isCurrentYear && isCurrentMonth && isCurrentDay;

      const calculateDate = d.getFullYear() + '-' + curMonth + '-' + curDate; // 当前年月日(比如:'2023-01-18')
      // 当前日期对应一周的日期数组
      const weekDateArr = getWeekDataList(calculateDate);
      console.log('当前日期对应一周的日期数组', weekDateArr);

      /** 处理签到类型 */
      let type = 1; // 签到类型
      if (item?.split('.')[0] * 1 < _curMonth) {
        // 上一个月
        type = 1;
      } else if (item?.split('.')[0] * 1 === _curMonth) {
        // 今月
        if (item?.split('.')[1] * 1 < _curDate) {
          // 今日之前
          type = 1;
        } else if (item?.split('.')[1] * 1 === _curDate) {
          // 今日
          type = 2;
        } else {
          // 今日之后
          type = 3;
        }
      } else {
        // 下一个月
        type = 3;
      }

      return (
        <div className="outerBox" key={`${currentYear}_${currentMonth}_${row}_${i}`}>
          <div className="innerContent">
            {/* 签到状态(星期排除处理)*/}
            {isNotWeek && statusMap[type]}
            {/* 今月的字体为黑色blackText,非今月的为灰色 */}
            <p className={`dateNum ${isCurrentDate ? 'blackText' : ''}`}>{isToday ? '今天' : item}</p>
          </div>
        </div>
      );
    })
  }

  return (
    <div className="calendar">
      <div className="date">
        {
          // 因为第一行需展示日期,所以最多7行
          Array(7).fill('').map((item, index) => {
            return (
              <div className='row' key={index}>{renderDays(index)}</div>
            )
          })
        }
      </div>
    </div>
  );
}

export default Calendar;

calendar/index.less

.calendar {
  width: 100%;
  height: 100%;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;

  .date {
    position: relative;
    width: 100%;
    height: 100%;
    .row {
        width: 100%;
        height: 140px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        /** 第一行日期单独写一个高度 */
        &:first-child {
            height: 36px;
        }
        &:not(:last-child) {
            margin-bottom: 20px;
        }
        
        .outerBox {
            width: calc(646px / 7);
            height: 100%;
            .innerContent {
                width: 100%;
                height: 100%;
                display: flex;
                flex-direction: column;
                justify-content: center;
                p {
                    margin: 0;
                }
                .dateNum {
                  text-align: center;
                  font-size: 26px;
                  font-family: PingFangSC-Regular, PingFang SC;
                  color: #B3B3B3;
                  line-height: 36px;
                }
              
                .blackText {
                  color: #555555;
                }    
                
                .status {
                    width: 84px;
                    height: 104px;
                    margin: auto;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    span {
                        font-size: 24px;
                        font-family: PingFangSC-Semibold, PingFang SC;
                        font-weight: 600;
                        color: #D9B27D;
                        line-height: 34px;
                    }
                }   
                /** 状态-过去 未签到 */
                .status1 {
                    background: url('../../../assets/signComponent/day_pass.png') no-repeat center/cover;
                }
                /** 状态-已签到 */
                .status2 {
                    background: url('../../../assets/signComponent/day_signed.png') no-repeat center/cover;
                }     
                /** 状态-将来 未签到 */
                .status3 {
                    background: url('../../../assets/signComponent/day_notSign.png') no-repeat center/cover;
            } 
          }
        }
    }    
  }
}
2、调用该组件 🍓

home.jsx

"use strict"

import React from "react";
import Calendar from "./calendar"; // 引入手写的日历组件
import "./home.less"

function Home() {

  return (
    <div className="home">
      {/* 日历组件 */}
      <Calendar />
    </div >
  )
}

export default Home

home.less

.home {
  width: 690px;
  height: 996px;
  margin: auto;
  background: #FFFFFC;
  box-shadow: 0px 6px 12px 0px rgb(0 0 0 / 8%);
  border-radius: 20px;
  padding: 32px 22px;
  box-sizing: border-box;
}

【二】JS-计算某一日期对应一周的日期 ⭐️

该方法改编自优秀的博文:https://blog.csdn.net/h__z__q/article/details/122110770?spm=1001.2014.3001.5501,感谢优秀的大佬~

/**
   * 计算某一日期对应一周的日期(比如:getWeekDataList('2023-01-18'); 结果为:['2023-01-16', '2023-01-17', '2023-01-18', '2023-01-19', '2023-01-20', '2023-01-21', '2023-01-22'])
   * @param {String} data 日期【格式: 年-月-日(xxxx-xx-xx)(比如:'2023-01-18')】
   * @returns 一个含周一到周日日期的数组
*/
function getWeekDataList(data) {
    // 根据日期获取本周周一~周日的年-月-日
    const weekList = [];
    const date = new Date(data);
    // 判断本日期是否为周日,获取本周一日期
    if (date.getDay() === 0) {
      date.setDate(date.getDate() - 6);
    } else {
      date.setDate(date.getDate() - date.getDay() + 1);
    }
    const myMonth = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : '' + (date.getMonth() + 1); // 月
    const myDate = date.getDate() < 10 ? '0' + date.getDate() : '' + date.getDate(); // 日
    weekList.push(date.getFullYear() + '-' + myMonth + '-' + myDate);
    // 获取周二以后日期
    for (let i = 0; i < 6; i++) {
      date.setDate(date.getDate() + 1);
      const myMonth = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : '' + (date.getMonth() + 1); // 月
      const myDate = date.getDate() < 10 ? '0' + date.getDate() : '' + date.getDate(); // 日	
      weekList.push(date.getFullYear() + '-' + myMonth + '-' + myDate);
    }
    // console.log('一个含周一到周日日期的数组', weekList);
    return weekList;
};

在这里插入图片描述
请添加图片描述

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小呀小萝卜儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值