这是 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