react 编写日历组件

简单的日历组件

import React, { Component } from "react";
import * as _ from "lodash";

const l = console.log;
const weeks = ["日", "一", "二", "三", "四", "五", "六"];
class Test extends Component {
  state = {};
  componentWillMount() {
    this.initState();
  }
  initState = ({ y, m } = {}) => {
    let date = new Date();
    let year = y || date.getFullYear(); // 本年
    let month = m || date.getMonth() + 1; // 本月
    l(`${year}年${month}月.`);

    let date2 = new Date(year, month, 0);
    let days = date2.getDate(); // 本月有多少天
    l(`本月有${days}天.`);

    date2.setDate(1);
    let day = date2.getDay(); // 本月第一天是星期几
    l(`本月第一天是星期${day}.`);

    let list = [];

    for (let i = 0; i < days + day; i++) {
      if (i < day) {
        list.push(0);
      } else {
        list.push(i - day + 1);
      }
    }
    let hlist = _.chunk(list, 7); // 转化为二维数组
    let len = hlist.length;
    let to = 7 - hlist[len - 1].length;

    // 循环尾部补空格
    for (let i = 0; i < to; i++) {
      hlist[len - 1].push(0);
    }
    this.setState({
      date,
      year,
      month,
      days,
      day,
      hlist,
    });
  };

  // 上月
  handlePrevMonth = () => {
    let prevMonth = this.state.month + -1;
    let prevYear = this.state.year;
    if (prevMonth < 1) {
      prevMonth = 12;
      prevYear -= 1;
    }
    this.initState({
      y: prevYear,
      m: prevMonth,
    });
  };

  // 下月
  handleNextMonth = () => {
    let nextMonth = this.state.month + 1;
    let nextYear = this.state.year;
    if (nextMonth > 12) {
      nextMonth = 1;
      nextYear += 1;
    }
    this.initState({
      y: nextYear,
      m: nextMonth,
    });
  };

  render() {
    const { year, month } = this.state;
    return (
      <>
        <h2>
          {year}年,{month}月
        </h2>
        <div>
          <button onClick={this.handlePrevMonth}>上月</button>
          <button onClick={this.handleNextMonth}>下月</button>
        </div>
        <table>
          <tbody>
            <tr>
              {weeks.map(el => (
                <th key={el}>{el}</th>
              ))}
            </tr>
            {this.state.hlist.map((el, i) => {
              return (
                <tr key={i}>
                  {el.map((n, ii) => (
                    <td key={ii}>{n}</td>
                  ))}
                </tr>
              );
            })}
          </tbody>
        </table>
      </>
    );
  }
}

export default Test;

2

import React, { Component } from "react";
import * as _ from "lodash";

class DateItem {
  /**
   *
   * @param  dayNum 日数, 如果和 new Date().getDate() 相等则是今天
   * @param  isSignIn=false 是否签到
   * @param  isShowSignIn=false 是否显示是否签到,大于今日和这个月的日期应该都不显示
   */
  constructor({ dayNum, isSignIn = false, isShowSignIn = false }) {
    Object.assign(this, {
      dayNum,
      isSignIn,
      isShowSignIn,
    });
  }
}

const l = console.log;
const weeks = ["日", "一", "二", "三", "四", "五", "六"];
class Test extends Component {
  state = {};
  componentWillMount() {
    this.initState();
  }
  initState = ({ y, m } = {}) => {
    const date = new Date();
    const year = y || date.getFullYear(); // 本年
    const month = m || date.getMonth() + 1; // 本月

    l(`${year}年${month}月.`);

    let date2 = new Date(year, month, 0);
    let days = date2.getDate(); // 本月有多少天
    l(`本月有${days}天.`);

    date2.setDate(1);
    let day = date2.getDay(); // 本月第一天是星期几
    l(`本月第一天是星期${day}.`);

    let list = [];
    const nowadays = date.getDate(); // 本日
    const thisMonth = date.getMonth() + 1; // 本月

    let isShowSignIn = false;
    const date2GtDate = date2 > date;
    const isThisMonth = month === thisMonth; // 选择的日期的月份是否是本月

    for (let i = 0; i < days + day; i++) {
      const dayNum = i - day + 1;
      if (date2GtDate) {
        isShowSignIn = false;
      } else {
        if (isThisMonth && i >= day + nowadays) {
          isShowSignIn = false;
        } else {
          isShowSignIn = true;
        }
      }

      if (i < day) {
        list.push(new DateItem({ dayNum: 0, isShowSignIn }));
      } else {
        list.push(new DateItem({ dayNum, isShowSignIn }));
      }
    }
    let hlist = this.getHlist(list, isShowSignIn);
    this.setState({
      date,
      year,
      month,
      days,
      day,
      list,
      hlist,
      nowadays,
      thisMonth,
    });
  };

  // 把一维日期切成二维日期
  getHlist = (list, isShowSignIn) => {
    let hlist = _.chunk(list, 7); // 转化为二维数组
    let len = hlist.length;
    let to = 7 - hlist[len - 1].length;

    // 循环尾部补空格
    for (let i = 0; i < to; i++) {
      hlist[len - 1].push(new DateItem({ dayNum: 0, isShowSignIn }));
    }
    return hlist;
  };

  // 上月
  handlePrevMonth = () => {
    let prevMonth = this.state.month + -1;
    let prevYear = this.state.year;
    if (prevMonth < 1) {
      prevMonth = 12;
      prevYear -= 1;
    }
    this.initState({
      y: prevYear,
      m: prevMonth,
    });
  };

  // 下月
  handleNextMonth = () => {
    let nextMonth = this.state.month + 1;
    let nextYear = this.state.year;
    if (nextMonth > 12) {
      nextMonth = 1;
      nextYear += 1;
    }
    this.initState({
      y: nextYear,
      m: nextMonth,
    });
  };

  // 点击每个日期
  handleDateItemClick = (dateItem, i, j) => () => {
    const { year, month, date, nowadays } = this.state;
    const { isShowSignIn, isSignIn, dayNum } = dateItem;
    if (dayNum === 0) return;
    const selectDate = new Date(`${year}-${month}-${dayNum}`);
    if (nowadays === dayNum) {
      l("签到");
    } else if (selectDate < date) {
      l("补签");
    }

    if (!isShowSignIn || isSignIn)
      // 不能签到的日期和已签到的日期直接返回
      return;

    this.setState(state => {
      const hlist = state.hlist.slice();
      hlist[i][j].isSignIn = true;
      return {
        hlist,
      };
    });
  };
  render() {
    const { year, month, nowadays, thisMonth } = this.state;
    return (
      <>
        <h2>
          {year}年,{month}月
        </h2>
        <div>
          <button onClick={this.handlePrevMonth}>上月</button>
          <button onClick={this.handleNextMonth}>下月</button>
          <button
            onClick={() => {
              this.initState();
            }}
          >
            今天
          </button>
        </div>
        <table>
          <tbody>
            <tr>
              {weeks.map(el => (
                <th key={el}>{el}</th>
              ))}
            </tr>
            {this.state.hlist.map((el, i) => {
              return (
                <tr key={i}>
                  {el.map((dateItem, j) => {
                    const dayNum = dateItem.dayNum;
                    const isSignIn = dateItem.isSignIn;
                    const isShowSignIn = dateItem.isShowSignIn;
                    return (
                      <td
                        key={j}
                        style={{
                          color:
                            dayNum === nowadays && month === thisMonth && "red",
                          textAlign: "center",
                          padding: 8,

                          border: "1px solid",
                          borderColor: dateItem.isSignIn
                            ? "red"
                            : "transparent",
                          opacity: dayNum === 0 ? 0 : 1,
                        }}
                        onClick={this.handleDateItemClick(dateItem, i, j)}
                      >
                        <div>{dayNum}</div>
                        {!!isShowSignIn && (
                          <div
                            style={{
                              whiteSpace: "nowrap",
                              fontSize: "12px",
                            }}
                          >
                            {!!isSignIn ? `已签到` : `未签到`}
                          </div>
                        )}
                      </td>
                    );
                  })}
                </tr>
              );
            })}
          </tbody>
        </table>
      </>
    );
  }
}

export default Test;
posted @ 2018-12-11 08:51  Ajanuw  阅读(2494)  评论(0编辑  收藏  举报