关于javascript:我的自定义日历

70次阅读

共计 11677 个字符,预计需要花费 30 分钟才能阅读完成。

这是 CalendarDate.js

import React, {useState, useEffect, useRef} from 'react'
import {Icon} from 'antd'
import './CalendarMore.css'
import './CalendarDate.css'
import {getMonth, weekArr} from './canlendarConfig'
import moment from 'moment'
function CalendarDate(props) {console.log('props', props);
    const [selectedValue, setSelectedValue] = useState([])// 选中的值
    const [canSelectedList, setCanSelectedList] = useState([])// 可选数组
    const [isShow, setIsShow] = useState(true)// 日历组件是否显示
    const {list = [], onChange, } = props
    const calendarDiv = useRef(null);
    // 设计默认值
    useEffect(() => {setSelectedValue(props.value || [])
        setCanSelectedList(list.map(one => one.code))
        document.addEventListener('click', outDivClickHandler);
        return () => {document.removeEventListener('click', outDivClickHandler);
        }
    }, [])
    function setSelectedValueChange(value) {setSelectedValue(value)
        onChange && onChange(value)
    }
    function outDivClickHandler(e) {let result = (calendarDiv.current).contains(e.target);
        if (!result) {setIsShow(false)
        }
    }
    return (<div ref={calendarDiv}>
            <div className='calendar-more' >
                <div className='show-box'  >
                    <div className='selected-show'>
                        {selectedValue.length > 0 ? selectedValue.map(one => <div key={one} className='selected-item days-width'>
                            {one}
                            <Icon type="close" style={{fontSize:'12px', cursor:'pointer'}} onClick={() => setSelectedValueChange(selectedValue.filter(item => item != one))} />
                        </div>) : <span style={{color: 'rgba(0, 0, 0, 0.30)' }}> 请抉择日期 </span>}
                    </div>
                    <div className='icon-calendar' onClick={() => setIsShow(!isShow)}><Icon type="calendar" /></div>
                </div>
            </div>
            {isShow ? <CalendarDays
                canSelectedList={canSelectedList}
                selectedValue={selectedValue}
                setSelectedValue={setSelectedValueChange}
            /> : null}
        </div>
    )
}
function CalendarDays(props) {const nowDate = moment().format('YYYY-M').split('-')
    const [yearNumber, setYearNumber] = useState(nowDate[0])
    const [monthNumber, setMonthNumber] = useState(nowDate[1])
    const {selectedValue = [], canSelectedList = [], setSelectedValue} = props

    console.log('canSelectedList', canSelectedList)

    function changeDays(value, isSelected) {if (isSelected) {setSelectedValue(selectedValue.filter(one => one != value))
        } else {setSelectedValue([...selectedValue, value])
        }
    }
    const daysList = getMonth(yearNumber, monthNumber)
    function changAddNumber() {let number = Number(monthNumber) + 1
        if (number == 13) {
            number = 1
            setYearNumber(Number(yearNumber) + 1)
        }
        setMonthNumber(number)
    }
    function changLessMonth() {let number = Number(monthNumber) - 1
        if (number == 0) {
            number = 12
            setYearNumber(Number(yearNumber) - 1)
        }
        setMonthNumber(number)
    }
    return <div className='calendar-days'>
        <div className='calendar-title'>
            <div><Icon type="double-left" onClick={() => setYearNumber((Number(yearNumber) - 1))} /></div>
            <div><Icon type="left" onClick={changLessMonth} /></div>
            <div className='year-number'>{yearNumber}年 {monthNumber} 月 </div>
            <div><Icon type="right" onClick={changAddNumber} /></div>
            <div><Icon type="double-right" onClick={() => setYearNumber(Number(yearNumber) + 1)} /></div>
        </div>
        <div className='calendar-days-content'>
            {weekArr.map(one => <div className='other-days' key={`week-${one}`}>{one}</div>)}
            {daysList.map(one => {const nowValue = moment(one.date).format('YYYYMMDD')
                const isSelected = selectedValue.includes(nowValue)
                return <div
                    onClick={() => changeDays(nowValue, isSelected)}
                    className={`common-days ${one.type == 'now' ? 'now-days' : 'other-days'} ${isSelected ? 'common-days-active' : ''}`}
                    key={`${one.type}-${one.value}`}>
                    {one.value}
                </div>
            })}

        </div>
    </div>
}

export default CalendarDate

这是 CalenDarDate.css

.calendar-days{
  position: absolute;
  border: 1px solid rgba(0, 0, 0, 0.15) ;
}
.calendar-days-content{
  display: flex;
  flex-wrap: wrap;
}
.other-days,.now-days{width:calc(100% / 7);
  text-align: center;
}
.other-days{color: #999;}
.now-days{color: #000;}
.common-days-active{
  background-color: #7300FF;
  color:#fff;
}
.common-days:hover{background-color: #efe6f5;}
.days-width{min-width: 86px;}

这是 calendarConfig.js

import moment from 'moment'
export const weekArr = ['一', '二', '三', '四', '五', '六', '七']
export const getMonth = (year, month) => {const date = `${year}-${month}`
    const lastArr = getLastDays(date)
    const nowMonthDays = moment(date).endOf('month').format('YYYY-MM-DD').split('-')[2]
    const size = 42 - nowMonthDays - lastArr.length
    let nextStr = moment(date).add(1, 'month').format('YYYY-MM')
    const nowArr = getDays(nowMonthDays, 'now', date)
    const nextArr = getDays(size, 'next', nextStr)
    console.log('data', date, lastArr, nowMonthDays, nextArr, nextStr);


    return [...lastArr, ...nowArr, ...nextArr]
}
// 获取上个月的日期参数
const getLastDays = (date) => {const start = moment(date).startOf('week').format('YYYY-MM-DD')
    const end = moment(start).endOf('month').format('YYYY-MM-DD')
    console.log('start', start, end, date);
    if (start == moment(date).format('YYYY-MM-DD')) {return []
    }
    return getDateArr(start, end)
}
// 获取 size 长度的数组
const getDays = (size, type, str) => {const data = []
    for (let i = 0; i < size; i++) {data.push({ value: i + 1, type: type, date: `${str}-${i + 1}` })
    }
    return data
}
// 获取上个月的数组
const getDateArr = (start, end) => {const min = start.split('-')
    let str = `${min[0]}-${min[1]}`
    const max = end.split('-')[2]
    let data = []
    console.log('min',min, max);
    for (let i = 0; i < max - min[2]; i++) {const value = Number(min[2]) + i + 1
        data.push({value: value, type: 'last', date: `${str}-${value}` })
    }
    return data
}

// const adasd = {
//     "name": "@param_age",
//     "title": "年龄",
//     "stype": 0,
//     "values": [
//         {
//             "name": "19-24 岁",
//             "code": "5"
//         }, {
//             "name": "25-29 岁",
//             "code": "1"
//         }
//     ]
// }


// function getAgeValue(data = {}) {//     let { values = [] } = data
//     console.log("getAgeValue -> values", values)
//     let str = ''
//     if (values.length > 0) {//         const firstValue = values[0].name.split('-')
//         let start = firstValue[0]
//         let end = firstValue[1].replace('岁', '')
//         if (values.length > 1) {//             const endValue = values[values.length - 1].name.split('-')
//             end = endValue[1].replace('岁', '')
//         }
//         str = `${start}-${end}`
//     }
//     return str
// }

这是 CalendarMore.js

import React, {useState, useEffect, useRef} from 'react'
import {Icon} from 'antd'
import moment from 'moment'
import './CalendarMore.css'

function CalendarMore(props) {const [selectedValue, setSelectedValue] = useState([])// 选中的值
    const [canSelectedList, setCanSelectedList] = useState([])// 可选数组
    const [isShow, setIsShow] = useState(false)// 日历组件是否显示
    const {list = [], onChange } = props
    const calendarDiv = useRef(null);
    // 设计默认值
    useEffect(() => {setSelectedValue(props.value || [])
        setCanSelectedList(list.map(one => one.code))
        document.addEventListener('click', outDivClickHandler);
        return () => {document.removeEventListener('click', outDivClickHandler);
        }
    }, [])
    function setSelectedValueChange(value) {setSelectedValue(value)
        onChange && onChange(value)
    }
    function outDivClickHandler(e) {let result = (calendarDiv.current).contains(e.target);
        if (!result) {setIsShow(false)
        }
    }
    return (<div ref={calendarDiv}>
            <div className='calendar-more' >
                <div className='show-box'  >
                    <div className='selected-show'>
                        {selectedValue.length > 0 ? selectedValue.map(one => <div key={one} className='selected-item'>
                            {one}
                            <Icon type="close" onClick={() => setSelectedValueChange(selectedValue.filter(item => item != one))} />
                        </div>) : <span style={{color: 'rgba(0, 0, 0, 0.30)' }}> 请抉择日期 </span>}
                    </div>
                    <div className='icon-calendar' onClick={() => setIsShow(!isShow)}><Icon type="calendar" /></div>
                </div>
            </div>
            {isShow ? <CalendarMonth
                canSelectedList={canSelectedList}
                selectedValue={selectedValue}
                setSelectedValue={setSelectedValueChange}
            /> : null}
        </div>
    )
}
function CalendarMonth(props) {const [yearNumber, setYearNumber] = useState(moment().year())
    const {selectedValue = [], canSelectedList = [], setSelectedValue} = props
    const monthArr = [{ name: 1, value: '01'},
        {name: 2, value: '02'},
        {name: 3, value: '03'},
        {name: 4, value: '04'},
        {name: 5, value: '05'},
        {name: 6, value: '06'},
        {name: 7, value: '07'},
        {name: 8, value: '08'},
        {name: 9, value: '09'},
        {name: 10, value: '10'},
        {name: 11, value: '11'},
        {name: 12, value: '12'},
    ]
    function selectedMonth(value, isSelected) {if (isSelected) {setSelectedValue(selectedValue.filter(one => one != value))
        } else {setSelectedValue([...selectedValue, value])
        }
    }

    return <div className='calendar-month'>
        <div className='calendar-content'>
            <div className='calendar-title'>
                <div><Icon type="double-left" onClick={() => setYearNumber(yearNumber - 1)} /></div>
                <div className='year-number'>{yearNumber}年 </div>
                <div><Icon type="double-right" onClick={() => setYearNumber(yearNumber + 1)} /></div>
            </div>
            <div className='month-show'>
                {monthArr.map(one => {const value = `${yearNumber}${one.value}`
                    const isCanSelected = canSelectedList.includes(value)
                    const isSelected = selectedValue.includes(value)
                    return isCanSelected ? <div key={one.name} className={`month-box ${isSelected ? 'month-box-active' : ''}`} onClick={() => selectedMonth(value, isSelected)}>{one.name}月 </div>
                        : <div key={one.name} className='month-box month-box-disable'>{one.name}月 </div>
                })}
            </div>
        </div>
    </div>
}
export default CalendarMore

这是 CalendarMore.css

.calendar-more{
  border:1px solid #DADADA;
  height: 30px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-variant: tabular-nums;
  list-style: none;
  -webkit-font-feature-settings: 'tnum';
  font-feature-settings: 'tnum', "tnum";
  position: relative;
  display: inline-block;
  width:100%;
  height: 32px;
  padding: 4px 11px;
  color: rgba(0, 0, 0, 0.65);
  font-size: 14px;
  line-height: 1.5;
  background-color: #fff;
  background-image: none;
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
}
.show-box{
  display: flex;
  width: 100%;
  justify-content: space-between;
}
.selected-show{width: calc(100% - 30px);
  display: flex;
  overflow-x: auto;
}
.icon-calendar{width: 20px;}
.calendar-month{position: relative;}
.calendar-content{
  position: fixed;
  z-index: 99999;
  width:300px;
  height:205px;
  background:rgba(255,255,255,1);
  box-shadow:0px 0px 6px 0px rgba(0,0,0,0.15);
  border-radius:3px;
}
.year-number{
  font-size:12px;
  font-family:SourceHanSansCN-Regular,SourceHanSansCN;
  font-weight:400;
  color:rgba(40,40,40,0.85);

}
.calendar-title{
  font-size:12px;
  font-family:SourceHanSansCN-Regular,SourceHanSansCN;
  display: flex;
  height: 36px;
  justify-content: space-between;
  border-bottom: 1px solid rgba(0, 0, 0, 0.15) ;
  padding: 0px 10px;
}
.month-show{
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  font-size: 12px;
}
.selected-show::-webkit-scrollbar {
  width: 3px;
  height: 3px;
}

/* Track */

.selected-show::-webkit-scrollbar-track {
  -webkit-box-shadow: none;
  border-radius: 0;
  background-color: transparent;
}

/* Handle */

.selected-show::-webkit-scrollbar-thumb {
  width: 2px !important;
  height: 6px !important;
  border-radius: 4px;
  background: rgba(111, 33, 212, 0.8);
  -webkit-box-shadow: inset 0 0 6px rgba(103, 82, 197, 0.3);
}

.selected-item{
  background: #F5f5f5;
  display: flex;
  align-items: center;
  color: #000;
  padding: 2px 5px;
  font-size: 12px;
  margin:0px 2px;
  min-width: 50px;
}
.month-box{
  width: 32px;
  height: 32px;
  margin: 5px calc((100% - 32*3px) /6);
  text-align: center;
  border-radius: 50%;
  line-height: 32px;
  -webkit-transition: all 0.3s;
  transition: all 0.3s;
}
.month-box:hover{background-color: #efe6f5;}
.month-box-active{
  background-color: #7300FF;
  color:#fff;
}
.month-box-disable{
  cursor:not-allowed;
  background-color: #ccc;
}
.month-box-disable:hover{
  cursor:not-allowed;
  background-color: #ccc;
}

这是 index.js

import React, {useEffect, useState} from 'react'
import {Form, Button, Input} from 'antd'
import CalendarMore from './CalendarMore'
import CalendarDate from './CalendarDate'
const data = [
    {
        "code": "202002",
        "name": "202002"
    },
    {
        "code": "201902",
        "name": "201902"
    },
    {
        "code": "202003",
        "name": "202003"
    },
    {
        "code": "201905",
        "name": "201905"
    },
    {
        "code": "201803",
        "name": "201803"
    },
    {
        "code": "202005",
        "name": "202005"
    }
]
function TestForm(props) {const [date, setDate] = useState([])
    function submit(e) {e.preventDefault();
        props.form.validateFields((err, values) => {if (!err) {console.log('Received values of form:', values);
            }
        });
    }
    useEffect(() => {setTimeout(() => {yarn(["202003", "202002"])
        }, 2000);
    }, [])
    const {getFieldDecorator, getFieldsError, getFieldError, isFieldTouched} = props.form;
    return (
        <div>
            <Form>
                {/* <Form.Item style={{ width: 300}}>
                    {getFieldDecorator('@param_month', {
                        initialValue: date,
                        rules: [{required: true, message: 'Please input your Password!'}],
                    })(<CalendarMore list={data} key={JSON.stringify(date)} />
                    )}
                </Form.Item> */}
                <Form.Item style={{width: 300}}>
                    {getFieldDecorator('@param_month23', {initialValue: ["20200322", "20200212"],
                        rules: [{required: true, message: 'Please input your Password!'}],
                    })(<CalendarDate list={data} key={JSON.stringify(date)} />
                    )}
                </Form.Item>
                <Button onClick={submit}> 提交 </Button>
            </Form>
        </div>
    )
}
const WrappedHorizontalLoginForm = Form.create('asd')(TestForm);
export default WrappedHorizontalLoginForm 

正文完
 0