Concis组件库封装——DatePicker日期选择器

1,111 阅读4分钟

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

DatePicker时间选择器的设计文档如下:

在这里插入图片描述 主体分为了单日选择器和时间区间选择器~ 单日选择器: 在这里插入图片描述

时间区间选择器: 在这里插入图片描述 组件的源码如下: DatePicker.tsx:

import React, { FC, memo, useState, useEffect, useCallback } from 'react'
import RangeDatePicker from './rangeDatePicker'
import { FieldTimeOutlined, CloseOutlined, CheckOutlined, LeftOutlined, RightOutlined, RollbackOutlined, DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons';
import "./index.module.less"

interface DatePickerProps {
    /**
   * @description 日期选择器类型(primary/input)仅支持非range
   * @default primary
   */
    type?: string
    /**
   * @description 设置日期区间选择器
   * @default false
   */
    showRange?: Boolean
    /**
   * @description 显示日期重置按钮
   * @default false
   */
    showClear?: Boolean
    /**
   * @description 方向
   * @default false
   */
    align?: string
    /**
   * @description 选择完毕后的回调函数
   * @default Function
   */
    handleChange?: Function
}
const monthList = ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"];

const DatePicker: FC<DatePickerProps> = (props) => {
    const { type, showRange, showClear, align, handleChange } = props;

    const [showTimeDialog, setShowTimeDialog] = useState(false);        //显示dialog
    const [renderShowDialog, setRenderShowDialog] = useState(false);
    const [nowDate, setNowDate] = useState({                        //选中的日期
        year: new Date().getFullYear(),
        month: new Date().getMonth() + 1,
        day: new Date().getDate()
    })
    const [thisMonthFirstDay, setThisMonthFirstDay] = useState(0);     //本月第一天是周几
    const [dayListArray, setDayListArray] = useState<Array<number>>([]);        //每月的日历
    const [pickStatus, setPickStatus] = useState(0);                        //timerpick状态,0表示选择日期,1表示改变月份,2表示改变年份
    const [iptValue, setIptValue] = useState<null | string>(null);                       //文本框输入的值
    const [yearList, setYearList] = useState<Array<number>>([2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, 2026]);

    useEffect(() => {
        window.addEventListener('click', () => {
            setShowTimeDialog(false)
            setTimeout(() => {
                setRenderShowDialog(false)
            }, 300)
        })
    }, [])
    useEffect(() => {
        const { year, month } = nowDate;
        const firstDay = new Date(`${year}/${month}/1`).getDay();
        const totalDay = new Date(year, month, 0).getDate()
        const dayList = new Array(firstDay).fill('');
        for (let i = 1; i < totalDay + 1; i++) {
            dayList.push(i)
        }
        setThisMonthFirstDay(firstDay);         //重新计算本月第一天为周几
        setDayListArray(dayList);               //重排本月日历

    }, [nowDate.year, nowDate.month])
    const openDialog = (e: any) => {
        e.stopPropagation()
        setShowTimeDialog(true);
        setRenderShowDialog(true)
    }
    const changeDay = (day: number) => {        //改变日期
        if (!day) return;
        setNowDate(old => {
            old.day = day;
            return { ...old }
        })
        handleChange && handleChange(`${nowDate.year}-${nowDate.month}-${nowDate.day}`);
        setShowTimeDialog(false);
        setTimeout(() => {
            setRenderShowDialog(false)
        }, 300)
    }
    const setToToday = () => {              //改变到今天
        const today = new Date();
        setNowDate(old => {
            old.year = today.getFullYear();
            old.month = today.getMonth() + 1;
            old.day = today.getDate();
            return { ...old };
        })
    }
    const changeToNextMonth = () => {           //改变到下个月
        const renderDate = {...nowDate};
        if (renderDate.month == 12) {               //12月新年
            renderDate.year += 1;
            renderDate.month = 1;
        } else {                            //普通递增
            renderDate.month += 1;
        }
        setNowDate(renderDate);
    }
    const changeToPreMonth = () => {
        const renderDate = {...nowDate};
        if (renderDate.month == 1) {               //12月新年
            renderDate.year -= 1;
            renderDate.month = 12;
        } else {                            //普通递增
            renderDate.month -= 1;
        }
        setNowDate(renderDate);
    }
    const changeMonth = (month: number) => {    //改变月份
        setNowDate(old => {
            old.month = month;
            return { ...old };
        })
        setPickStatus(0);
    }
    const changeYear = (year: number) => {         //改变年份
        setNowDate(old => {
            old.year = year;
            return { ...old };
        })
        setPickStatus(0);
    }
    const bindIptText = (e: any) => {           //绑定文本框
        setIptValue(e.target.value);
    }
    const enterChangeDate = (e: any) => {       //回车确认更改
        if (e.keyCode == 13) {       //回车
            if (iptValue !== null) {
                if (/^([1-2]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|30|31)$/.test(iptValue)) {
                    const inputValue = iptValue.split('-');
                    setNowDate(old => {
                        old.year = Number(inputValue[0]);
                        old.month = Number(inputValue[1]);
                        old.day = Number(inputValue[2]);
                        return { ...old };
                    })
                    handleChange && handleChange(`${Number(inputValue[0])}-${Number(inputValue[1])}-${Number(inputValue[2])}`);
                }
            }
            setIptValue(null);
            setShowTimeDialog(false);
            setTimeout(() => {
                setRenderShowDialog(false)
            }, 300)
        }
    }
    const blurInput = () => {                   //文本框失去焦点
        if (iptValue !== null) {
            if (/^([1-2]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|30|31)$/.test(iptValue)) {
                const inputValue = iptValue.split('-');
                setNowDate(old => {
                    old.year = Number(inputValue[0]);
                    old.month = Number(inputValue[1]);
                    old.day = Number(inputValue[2]);
                    return { ...old };
                })
            }
        }
        setIptValue(null);
    }
    const setNextGroupYear = () => {            //设定下一组年份
        setYearList(old => {
            return [...old.map(y => y + 9)]
        })
    }
    const setPreGroupYear = () => {
        setYearList(old => {
            return [...old.map(y => y - 9)]
        })
    }
    const clearDate = () => {                   //清空
        setNowDate(old => {
            old.year = new Date().getFullYear(),
                old.month = new Date().getMonth() + 1,
                old.day = new Date().getDate()
            return { ...old }
        })
        setIptValue(null);
    }
    const rangeDatePickChangeCallback = (start: string, end: string) => {
        handleChange && handleChange(start, end);
    }
    const activeStyle = {           //选中的所有样式
        result: {
            letterSpacing: "normal",
            color: "#1890FF",
            width: "120px"
        },
        icon: {
            opacity: 1,
            marginLeft: "5px"
        },
        checkBox: {
            opacity: 1,
        },
        dayActive: {
            backgroundColor: "#1890FF",
            color: "#fff",
            fontWeight: "bold",
            borderRadius: "5px"
        }
    }
    const alignFn = useCallback(() => {             //对齐方式
        if(!align) {
            return {
                bottom: {
                    top: "40px"
                }
            }
        }
        return {
            right: {
                left: "170px",
                bottom: "20px",
            },
            left: {
                right: "800px",
                bottom: "40px",
            },
            top: {
                bottom: "40px",
            },
            bottom: {
                top: "40px"
            }
        }[align]
    }, [align])

    return (

        showRange
            ?
            <RangeDatePicker showClear={showClear} align={align ? align : "bottom"} handleChange={rangeDatePickChangeCallback} />
            :
            <div className="time-picker">
                {
                    (type == "primary"
                        ||
                        !type)
                    &&
                    <div className="result" style={showTimeDialog ? activeStyle.result : {}} onClick={(e) => openDialog(e)}>
                        <span>{nowDate.year}-{nowDate.month}-{nowDate.day}</span>
                        <div className="icon" style={showTimeDialog ? activeStyle.icon : {}}>
                            <FieldTimeOutlined />
                        </div>
                    </div>
                }
                {
                    type == "input"
                    &&
                    <div>
                        <input
                            className="input"
                            value={iptValue !== null ? iptValue : `${nowDate.year}-${nowDate.month}-${nowDate.day}`}
                            onClick={(e) => openDialog(e)}
                            onChange={(e) => bindIptText(e)}
                            onKeyDown={(e) => enterChangeDate(e)}
                            onBlur={blurInput}
                        />
                        {
                            showClear
                            &&
                            <CloseOutlined style={{ position: 'relative', right: '15px', fontSize: '12px', cursor: 'pointer' }} onClick={clearDate} />
                        }
                    </div>
                }
                {
                    renderShowDialog
                    &&
                <div className="check-box" style={{...showTimeDialog ? activeStyle.checkBox : {}, ...alignFn()} as any} onClick={(e) => e.stopPropagation()}>
                    <div className="top-bar">
                        <b className="year" onClick={() => setPickStatus(2)}>{nowDate.year}</b>
                        <b className="month" onClick={() => setPickStatus(1)} style={{ marginRight: "20px" }}>{nowDate.month}</b>
                        <div className="close-icon" onClick={() => {
                            setShowTimeDialog(false)
                            setTimeout(() => {
                                setRenderShowDialog(false)
                            }, 300)
                        }}>
                            <CloseOutlined />
                        </div>
                    </div>
                    <div className="date-content">
                        {/* 日历 */}
                        {
                            pickStatus == 0
                            &&
                            <>
                                <div className="week">
                                    <div></div>
                                    <div></div>
                                    <div></div>
                                    <div></div>
                                    <div></div>
                                    <div></div>
                                    <div></div>
                                </div>
                                <div className="day-list">
                                    {
                                        dayListArray.map((day, index) => {
                                            return (
                                                <div key={index} className={day ? "day" : "white"} style={nowDate.day == day ? activeStyle.dayActive : {}} onClick={() => changeDay(day)}>
                                                    {day}
                                                </div>
                                            )
                                        })
                                    }
                                </div>
                            </>
                        }
                        {/* 月份选择框 */}
                        {
                            pickStatus == 1
                            &&
                            <div className="month-toggle-box">
                                {
                                    monthList.map((m: string, index) => {
                                        return (
                                            <div key={m} className="month" style={index + 1 == nowDate.month ? activeStyle.dayActive : {}} onClick={() => changeMonth(index + 1)}>
                                                {m}
                                            </div>
                                        )
                                    })
                                }
                            </div>
                        }
                        {/* 年份选择框 */}
                        {
                            pickStatus == 2
                            &&
                            <div className="year-toggle-box">
                                <div className="toggle-bar">
                                    <DoubleLeftOutlined style={{ cursor: "pointer" }} onClick={setPreGroupYear} />
                                    <span>{yearList[0]}-{yearList[8]}</span>
                                    <DoubleRightOutlined style={{ cursor: "pointer" }} onClick={setNextGroupYear} />
                                </div>
                                <div className="list">
                                    {
                                        yearList.map((m: number) => {
                                            return (
                                                <div key={m} className="year" style={m == nowDate.year ? activeStyle.dayActive : {}} onClick={() => changeYear(m)}>
                                                    {m}
                                                </div>
                                            )
                                        })
                                    }
                                </div>
                            </div>
                        }

                    </div>
                    <div className="time-footer">
                        {
                            pickStatus == 0
                            &&
                            <>
                                <div className="today" onClick={setToToday}>
                                    <span>今天</span>
                                    <CheckOutlined />
                                </div>
                                <div className="toggle-month">
                                    <LeftOutlined style={{ marginRight: "5px" }} onClick={changeToPreMonth} />
                                    <RightOutlined onClick={changeToNextMonth} />
                                </div>
                            </>
                        }
                        {
                            (pickStatus == 1 || pickStatus == 2)
                            &&
                            <>
                                <div></div>
                                <div className="go-back-icon" onClick={() => setPickStatus(0)}>
                                    <RollbackOutlined />
                                </div>
                            </>
                        }
                    </div>
                </div>
}
            </div>


    )
}

export default memo(DatePicker);

RangeDatePicker.tsx:

import React, { useEffect, FC, memo, useState, useCallback } from 'react'
import { DoubleLeftOutlined, LeftOutlined, DoubleRightOutlined, RightOutlined, SwapRightOutlined } from '@ant-design/icons'
import Input from '../../Input'
import './index.module.less'

interface RangeProps {
    showClear?: Boolean
    align?: string
    handleChange?: Function
}
const RangeDatePicker: FC<RangeProps> = (props) => {
    const { showClear, align, handleChange } = props
    const [startDate, setStartDate] = useState({
        startYear: new Date().getFullYear(),
        startMonth: new Date().getMonth() + 1,
        startDay: new Date().getDate()
    })
    const [endDate, setEndDate] = useState({
        endYear: new Date().getFullYear(),
        endMonth: new Date().getMonth() + 2,
        endDay: new Date().getDate()
    })
    const [startTime, setStartTime] = useState('');
    const [endTime, setEndTime] = useState('')
    const [startMonthFirstDay, setStartMonthFirstDay] = useState(0);     //本月第一天是周几
    const [endMonthFirstDay, setEndMonthFirstDay] = useState(0);     //本月第一天是周几
    const [startDayListArray, setStartDayListArray] = useState<Array<number>>([]);        //start月的日历
    const [endDayListArray, setEndDayListArray] = useState<Array<number>>([]);        //end月的日历
    const [showTimeDiaglog, setShowTimeDialog] = useState(false);                       //日期选择器dialog show
    const [renderShowDialog, setRenderShowDialog] = useState(false);
    const [chooseStatus, setChooseStatus] = useState({
        start: false,
        end: false
    });                    //是否被选择过

    let activeBorderDom: Element | null = document.querySelector('.activeBorder');

    useEffect(() => {
        const { startYear, startMonth } = startDate;
        const { endYear, endMonth } = endDate;
        const startFirstDay = new Date(`${startYear}/${startMonth}/1`).getDay();
        const endFirstDay = new Date(`${endYear}/${endMonth}/1`).getDay();
        const startTotalDay = new Date(startYear, startMonth, 0).getDate()
        const endTotalDay = new Date(endYear, endMonth, 0).getDate()
        const startDayList = new Array(startFirstDay).fill('');
        const endDayList = new Array(endFirstDay).fill('');
        for (let i = 1; i < startTotalDay + 1; i++) {
            startDayList.push(i)
        }
        for (let i = 1; i < endTotalDay + 1; i++) {
            endDayList.push(i)
        }
        setStartDayListArray(startDayList);
        setStartMonthFirstDay(startFirstDay);
        setEndDayListArray(endDayList);
        setEndMonthFirstDay(endFirstDay);
    }, [startDate.startYear, startDate.startMonth, endDate.endYear, endDate.endMonth])
    useEffect(() => {
        window.addEventListener('click', () => {
            setShowTimeDialog(false)
            setTimeout(() => {
                setRenderShowDialog(false)
            }, 300)
        })
    }, [])
    useEffect(() => {
        if(chooseStatus.start && chooseStatus.end) {
            setShowTimeDialog(false)
            setTimeout(() => {
                setRenderShowDialog(false)
            }, 300);
            setChooseStatus(old => {
                old.start = false;
                old.end = false;
                return {...old};
            })
            handleChange && handleChange(startTime, endTime);
        }
    }, [chooseStatus])

    const startIptFocus = () => {
        setShowTimeDialog(true);
        setRenderShowDialog(true);
        (activeBorderDom as any).style.left = "0";
    }
    const endIptFocus = () => {
        setShowTimeDialog(true);
        setRenderShowDialog(true);
        (activeBorderDom as any).style.left = "190px";
    }
    const preYear = (type: string) => {         //切换上一年
        if (type == "start") {
            const renderDate = {...startDate};
            renderDate.startYear -= 1;
            setStartDate(renderDate);
        } else if (type == "end") {
            if (endDate.endYear > startDate.startYear) {
                const renderDate = {...endDate};
                renderDate.endYear -= 1;
                setEndDate(renderDate)
            }
        }
    }
    const nextYear = (type: string) => {        //切换下一年
        if (type == "start") {
            if (startDate.startYear < endDate.endYear) {
                const renderDate = {...startDate};
                renderDate.startYear += 1;
                setStartDate(renderDate);
            }
        } else if (type == "end") {
            const renderDate = {...endDate};
            renderDate.endYear += 1;
            setEndDate(renderDate)
        }
    }
    const preMonth = (type: string) => {        //切换上一个月
        if (type == "start") {
            const renderDate = {...startDate};
            if (renderDate.startMonth == 1) {
                renderDate.startMonth = 12;
                renderDate.startYear -= 1;
            } else {
                renderDate.startMonth -= 1;
            }
            setStartDate(renderDate);
        } else if (type == "end") {
            if (endDate.endYear == startDate.startYear && endDate.endMonth == startDate.startMonth) {
                return;
            } else {
                const renderDate = {...endDate};
                if (renderDate.endMonth == 1) {
                    renderDate.endMonth = 12;
                    renderDate.endYear -= 1;
                } else {
                    renderDate.endMonth -= 1;
                }
                if (renderDate.endDay < startDate.startDay) {
                    renderDate.endDay = startDate.startDay;
                }
                setEndDate(renderDate);
            }
        }
    }
    const nextMonth = (type: string) => {      //切换下一个月
        if (type == "start") {
            if (endDate.endYear == startDate.startYear && endDate.endMonth == startDate.startMonth) {
                return;
            } else {
                const renderDate = {...startDate};
                if (renderDate.startMonth == 12) {
                    renderDate.startMonth = 1;
                    renderDate.startYear += 1;
                } else {
                    renderDate.startMonth += 1;
                }
                setStartDate(renderDate);
            }
        } else if (type == "end") {
            const renderDate = {...endDate};
            if (renderDate.endMonth == 12) {
                renderDate.endMonth = 1;
                renderDate.endYear += 1;
            } else {
                renderDate.endMonth += 1;
            }
            setEndDate(renderDate);
        }
    }
    const chooseStartDay = (day: number | string) => {          //选择开始日期
        if (day == "") return;
        setStartDate(old => {
            old.startDay = day as number;
            return { ...old };
        })
        setChooseStatus(old => {
            old.start = true;
            return {...old};
        })
        setStartTime(`${startDate.startYear}-${startDate.startMonth}-${day}`);
        if (startDate.startYear == endDate.endYear && startDate.startMonth == endDate.endMonth) {
            if (day > endDate.endDay) {
                setEndDate(old => {
                    old.endDay = day as number;
                    return { ...old };
                })
            }
        }
    }
    const chooseEndDay = (day: number | string) => {            //选择结束日期
        if (startDate.startYear == endDate.endYear && startDate.startMonth == endDate.endMonth) {
            if (day < startDate.startDay) {
                return;
            }
        }
        setChooseStatus(old => {
            old.end = true;
            return {...old};
        })
        setEndDate(old => {
            old.endDay = day as number;
            return { ...old };
        })
        setEndTime(`${endDate.endYear}-${endDate.endMonth}-${day}`)
    }
    const enterChangeStartTime = (e: any) => {              //回车改变
        if (e.keyCode == 13) {
            if (/^([1-2]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|30|31)$/.test(startTime)) {
                const start = startTime.split('-');
                if (Number(start[0]) <= endDate.endYear && Number(start[1]) <= endDate.endMonth && Number(start[2]) <= endDate.endDay) {
                    setStartDate(old => {
                        old.startYear = Number(start[0]);
                        old.startMonth = Number(start[1]);
                        old.startDay = Number(start[2]);
                        return { ...old };
                    })
                    setChooseStatus(old => {
                        old.start = true;
                        return {...old}
                    })
                } else {
                    setStartTime('');
                }
            } else {
                setStartTime('');
            }
        }
    }
    const blurStartTime = () => {                       //失去焦点
        if (!/^([1-2]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|30|31)$/.test(startTime)) {
            setStartTime('');
        }
    }
    const enterChangeEndTime = (e: any) => {              //回车改变
        if (e.keyCode == 13) {
            if (/^([1-2]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|30|31)$/.test(endTime)) {
                const start = endTime.split('-');
                if (Number(start[0]) >= startDate.startYear && Number(start[1]) >= startDate.startMonth && Number(start[2]) >= startDate.startDay) {
                    setEndDate(old => {
                        old.endYear = Number(start[0]);
                        old.endMonth = Number(start[1]);
                        old.endDay = Number(start[2]);
                        return { ...old };
                    })
                    setChooseStatus(old => {
                        old.end = true;
                        return {...old}
                    })
                } else {
                    setEndTime('');
                }
            } else {
                setEndTime('');
            }
        }
    }
    const blurEndTime = () => {                       //失去焦点
        if (!/^([1-2]\d{3})-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2][0-9]|30|31)$/.test(endTime)) {
            setEndTime('');
        }
    }
    const clearStartTime = () => {                  //清空开始时间
        setStartTime('');
        setStartDate(old => {
            const now = new Date();
            old.startDay = now.getDate();
            old.startMonth = now.getMonth() + 1;
            old.startYear = now.getFullYear();
            return { ...old };
        })
    }
    const clearEndTime = () => {                    //清空结束时间
        setEndTime('');
        setEndDate(old => {
            const now = new Date();
            old.endDay = now.getDate();
            old.endMonth = now.getMonth() + 1;
            old.endYear = now.getFullYear();
            return { ...old };
        })
    }
    const activeStyles = () => {                        //选中的样式
        return {
            activeDay: {
                color: "#fff",
                background: "#1890FF",
                fontWeight: "bold",
                borderRadius: "5px"
            },
            showDialog: {
                opacity: 1
            }
        }
    }
    const alignFn = useCallback(() => {
        if (!align) {
            return {
                bottom: {
                    top: "40px"
                }
            }
        }
        return {
            right: {
                left: "360px",
                bottom: "20px",
            },
            left: {
                right: "600px",
                bottom: "20px",
            },
            top: {
                bottom: "40px",
            },
            bottom: {
                top: "40px"
            }
        }[align]
    }, [align])
    const disabledClass = useCallback((day: number | string) => {
        if (day == "") {
            return "white"
        }
        if (startDate.startYear == endDate.endYear && startDate.startMonth == endDate.endMonth) {
            if (day < startDate.startDay) {
                return "disabled-day"
            }
            return "day-box";
        }
        return "day-box";
    }, [startDate, endDate])
    return (
        <div className="range" onClick={(e) => e.stopPropagation()} >
            <div className="rangePicker" onClick={(e) => e.stopPropagation()}>
                <Input
                    placeholder="请输入开始日期"
                    defaultValue={startTime ? startTime : `${startDate.startYear}-${startDate.startMonth}-${startDate.startDay}`}
                    handleIptChange={(v: string) => setStartTime(v)}
                    handleIptFocus={startIptFocus}
                    handleKeyDown={(e: any) => enterChangeStartTime(e)}
                    handleIptBlur={blurStartTime}
                    clearCallback={clearStartTime}
                    showClear={showClear as boolean} />
                <SwapRightOutlined style={{ color: "#cccccc", fontSize: "20px" }} />
                <Input
                    placeholder="请输入结束日期"
                    defaultValue={endTime ? endTime : `${endDate.endYear}-${endDate.endMonth}-${endDate.endDay}`}
                    handleIptChange={(v: string) => setEndTime(v)}
                    handleIptFocus={endIptFocus}
                    handleKeyDown={(e: any) => enterChangeEndTime(e)}
                    handleIptBlur={blurEndTime}
                    clearCallback={clearEndTime}
                    showClear={showClear as boolean} />
                <div className="activeBorder"></div>
            </div>
            {
                renderShowDialog
                &&
                <div className="date-box" onClick={(e) => e.stopPropagation()} style={{ ...showTimeDiaglog ? activeStyles().showDialog : {}, ...alignFn() } as any}>
                    <div className="left">
                        <div className="top-bar">
                            <div className="icon">
                                <DoubleLeftOutlined style={{ cursor: "pointer" }} onClick={() => preYear('start')} />
                                <LeftOutlined style={{ marginLeft: "10px", cursor: "pointer" }} onClick={() => preMonth('start')} />
                            </div>
                            <div className="info">
                                {startDate.startYear}年  {startDate.startMonth}月
                            </div>
                            <div>
                                <RightOutlined style={{ cursor: "pointer" }} onClick={() => nextMonth('start')} />
                                <DoubleRightOutlined style={{ marginLeft: "10px", cursor: "pointer" }} onClick={() => nextYear('start')} />

                            </div>
                        </div>
                        <div className="week">
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                        </div>
                        <div className="day-list">
                            {
                                startDayListArray.map((i: string | number, index) => {
                                    return (
                                        <div key={index} className={i == "" ? "white" : "box-list"} style={i == startDate.startDay ? activeStyles().activeDay : {}} onClick={() => chooseStartDay(Number(i))}>
                                            {i}
                                        </div>
                                    )
                                })
                            }
                        </div>
                    </div>
                    <div className="right">
                        <div className="top-bar">
                            <div>
                                <DoubleLeftOutlined style={{ cursor: "pointer" }} onClick={() => preYear('end')} />
                                <LeftOutlined style={{ marginLeft: "10px", cursor: "pointer" }} onClick={() => preMonth('end')} />
                            </div>
                            <div className="info">
                                {endDate.endYear}年  {endDate.endMonth}月
                            </div>

                            <div className="icon">
                                <RightOutlined style={{ cursor: "pointer" }} onClick={() => nextMonth('end')} />
                                <DoubleRightOutlined style={{ marginLeft: "10px", cursor: "pointer" }} onClick={() => nextYear('end')} />
                            </div>
                        </div>
                        <div className="week">
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                            <div></div>
                        </div>
                        <div className="day-list">
                            {
                                endDayListArray.map((i: string | number, index) => {
                                    return (
                                        <div key={index} className={disabledClass(i)} style={i == endDate.endDay ? activeStyles().activeDay : {}} onClick={() => chooseEndDay(Number(i))}>
                                            {i}
                                        </div>
                                    )
                                })
                            }
                        </div>
                    </div>
                </div>
            }
        </div>
    )
}

export default memo(RangeDatePicker);

设计思路主要就是找到每个月的第一天是周几,将这个月的日历排版做好,主要用到了Date中的getDay和getDate,getDay来获取某个月的第一天为周几;getDate来统计某个月一共有多少天,将日历设计为数组的形式。 React-View-UI日期选择器文档链接在这里~ 值得一提的是时间区间选择器支持跨多个月多个年来进行选择,这也是我对于自身的需求来进行市场组件扩充的一个点。 如果你对React-View-UI有兴趣,欢迎下载体验留言,有BUG欢迎吐槽~~

谢谢阅读