共计 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
正文完
发表至: javascript
2021-09-27