手寫一個react日曆超級簡單

概述

一個超級簡單的日曆,日曆核心代碼只有十幾行,方便之後擴展成日程管理。源碼點擊這裏css

前言

日曆或者日程管理,在項目中是個高頻使用的組件,常常會碰到日程管理這種需求,網上已經有不少成熟的庫,可是產品經理的思惟是你我沒法揣測的,因此先儲備一下,作個簡單的日曆,方便之後用的的時候直接用,代碼使用react寫的,可是核心的日曆計算思想能夠用到各類框架中。react

實現

首先看看最終實現的效果

能夠看到一個能查看上一個月或者下一個月的簡單日曆。git

日曆的計算的核心就是經過date.setdate()方法,能夠獲取到相對於當前日期的某天,好比new Date().setdate(1)就是當前日期的下一天github

代碼很簡單也有註釋,就很少贅述,有不懂的地方留言,秒回數組

import React, {Component} from 'react';
import style from './style.use.less'

export default class Test extends Component {
    constructor(props) {
        super(props);
        this.state = {
            currentDay: '',
            currentMonth: '', 
            currentYear: '', 
            weekList: [
                {name: '一', className: ''},
                {name: '二', className: ''},
                {name: '三', className: ''},
                {name: '四', className: ''},
                {name: '五', className: ''},
                {name: '六', className: ''},
                {name: '日', className: ''}
            ],
            dayList: []
        }

        this.initCalendar = this.initCalendar.bind(this);
        this.renderHeader = this.renderHeader.bind(this);
        this.renderBody = this.renderBody.bind(this);
        this.preMonth = this.preMonth.bind(this);
        this.nextMonth = this.nextMonth.bind(this);
    }

    componentWillMount() {
      // style.use() // 須要配置loader 能夠直接註釋 忽略掉  實現每一個模塊卸載以後 css也會銷燬 能夠看以前寫的一篇react css局部做用域的文章
    }

    componentWillUnmount() {
       // style.unuse() // 須要配置loader 能夠直接註釋 忽略掉 實現每一個模塊卸載以後 css也會銷燬 能夠看以前寫的一篇react css局部做用域的文章
    }

    componentDidMount() {
        this.initCalendar()
    }

    // 獲取當前date的當月第一天的字符串形式
    getMonthFirstDate(date) {
        let nowYear = date.getFullYear(); // 獲取年份
        let nowMonth = date.getMonth()+1; // 獲取月份
        return  `${nowYear}-${nowMonth}-01`
    }

    // 獲取當前date的字符串形式
    getDateString(date) {
        let nowYear = date.getFullYear(); // 獲取年份
        let nowMonth = date.getMonth()+1; // 獲取月份
        let day = date.getDate();
        day = day < 10 ? '0' + day : day;
        return  `${nowYear}-${nowMonth}-${day}`
    }

    // 上個月
    preMonth() {
        let date = new Date(`${this.state.currentYear}-${this.state.currentMonth}-${this.state.currentDay}`)
        let preMonthFirstDate = new Date(this.getMonthFirstDate(new Date(date.setDate(0)))); // 0 是上個月最後一天
        this.initCalendar(preMonthFirstDate)
    }

    // 下個月
    nextMonth() {
        let date = new Date(`${this.state.currentYear}-${this.state.currentMonth}-${this.state.currentDay}`)
        let nextMonthFirstDate = new Date(this.getMonthFirstDate(new Date(date.setDate(33))));
        this.initCalendar(nextMonthFirstDate)
    }


    // 初始化日曆
    initCalendar(currentDate) {
        
        let nowDate = currentDate ? currentDate : new Date();
        let nowMonthFirstDate = this.getMonthFirstDate(nowDate) // 獲取當月1號日期
        let nowWeek = new Date(nowMonthFirstDate).getDay() ? new Date(nowMonthFirstDate).getDay() : 7; // 獲取星期
        let newDateList = []; // 建立日期數組
        let startDay =  2 - nowWeek; // 開始日期的下標  覺得 setDate(0)是上個月最後一天  因此是2-nowWeek
        
        let showDayLength = nowWeek < 6 ? 35 : 42;  // 若是5行能顯示下一個月 就只顯示5行
        // 循環處理 獲取日曆上應該顯示的日期
        for (let i = startDay; i < startDay + showDayLength; i++) {
            let date = new Date(new Date(nowMonthFirstDate).setDate(i)); // 獲取時間對象
            let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() // 小於9的數字前面加0
            let dayObject = {
                date: this.getDateString(date),
                day,
                className: '',
            }
            // new Date(str).toDateString() === new Date().toDateString()
            if (date.toDateString() === new Date().toDateString()) {
                dayObject.className = 'today'
            }
            newDateList.push(dayObject)
        }

        this.setState((pre) => {
            return {
                dayList: newDateList,
                currentDay: nowDate.getDate(),
                currentMonth: nowDate.getMonth() + 1 >= 10 ? nowDate.getMonth() + 1 : '0' + (nowDate.getMonth() + 1),
                currentYear: nowDate.getFullYear(),
            }
        })

    }

    renderHeader() {
        return(
            <div className = 'calendar-header'>
                <div className = 'calendar-header-left'>
                    <button onClick = {this.preMonth}>上個月</button>
                </div>
                <div className = ''>
                    {this.state.currentYear}年{this.state.currentMonth}月
                </div>
                <div className = 'calendar-header-right'>
                    <button onClick = {this.nextMonth}>下個月</button>
                </div>
            </div>
        )
    }

    renderBody() {
        return(
            <div className = 'calendar-body'>
                <div className = 'week-container'>
                    {this.state.weekList.map(week => {
                        return <div key = {week.name} className = {`week ${week.className}`}>{week.name}</div>
                    })}
                </div>
                <div className = 'day-container'>
                    {this.state.dayList.map( (dayObject, index) => {
                        return <div key = {index} className = {`day ${dayObject.className}`}>{dayObject.day}</div>
                    })}
                </div>
            </div>
        )
    }

    render() {
        return(
            <div className = 'calendar'>
                {this.renderHeader()}
                {this.renderBody()}
            </div>
        )
    }
}

css文件框架

.calendar {
    width: 320px;
    margin-top: 40px;
    .calendar-header {
        display: flex;
        justify-content: space-between;
        padding: 14px 12px; 
    }
    .calendar-body {
        .week-container {
            display: flex;
            flex-wrap: wrap;
            justify-content: space-around;
            margin-bottom: 10px;
            .week {
                &:nth-child(6), &:nth-child(7){
                    color: #e02d2d;
                }
                width: 14.2%;
                display: inline-block;
                text-align: center;
            }
        }

        .day-container {
            height: 140px;
            display: flex;
            flex-wrap: wrap;
            justify-content: space-around;
            .day {
                width: 14.2%;
                display: inline-block;
                text-align: center;
                &:nth-child(7n-1){
                    color: #e02d2d;
                }
                &:nth-child(7n){
                    color: #e02d2d;
                }
                &.today {
                    color: green;
                }
            }
 
        }
    }
}
相關文章
相關標籤/搜索