antd 版本 3.19.3
先说一下我遇到的问题,项目中需要做多日期对比,本来想使用DatePicker
组件,每次选择一个日期,不能一次选择多个,操作起来相对有点麻烦(虽说实现起来很容易),于是,就想结合Select
和Calendar
组件一起使用,想法是很美好的,操作起来就困难重重了,我想要的效果如下图:
采用的是Select
的中 dropdownRender
自定义下拉框内容,但是自定义内容中包含Select
的话就会因失去焦点而关闭,无法进行二次选择,于是上网查了很多资料,都说如下方法可以解决这个问题,尝试了很多次都无效,不知道是不是我写法不对?时间很紧,不能因为一种方法而卡死,于是就换了一种思路,自己写一个类似Select
的组件不就行了,这样就不会又失去焦点的问题了,于是就选择了Dropdown
,只要效果一样,谁在乎你怎么实现的。
javascript
<Select
dropdownRender={() => (
<div
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
}}
>
Some Content
</div>
)}
/>
对于 Calendar
组件,要使用dateFullCellRender
,重新设置单元格,方便添加选中样式,只需要稍微修改一下样式就可以了。
css
// CalendarPage.css
.my_calendar .ant-fullcalendar-cell .ant-fullcalendar-selected-day .ant-fullcalendar-value {
color: #fff !important;
background: #1677ff !important;
}
.my_calendar .ant-fullcalendar-cell.ant-fullcalendar-selected-day .ant-fullcalendar-value {
color: unset;
background: unset;
}
.my_calendar_menu {
max-height: 300px;
overflow: auto;
}
Calendar
组件二次封装
javascript
import React from 'react';
import { Calendar, Card, Row, Col, Menu, Dropdown, Button } from 'antd'
import { DownOutlined } from '@ant-design/icons'
import moment from 'moment'
import './CalendarPage.css'
const dateFormat = 'YYYY-MM-DD'
export default function CalendarPage(props) {
const { values, handleSelect, ...resProps } = props
return (
<Card
bodyStyle={{ padding: 0, width: 300 }}
onMouseDown={e => {
e.preventDefault()
}}
style={{ width: 300 }}
>
<Calendar
headerRender={({ value, type, onChange, onTypeChange }) => {
const start = 0
const end = 12
const monthOptions = []
const current = value.clone()
const localeData = value.localeData()
const months = []
for (let i = 0; i < 12; i++) {
current.month(i)
months.push(localeData.monthsShort(current))
}
for (let index = start; index < end; index++) {
monthOptions.push(
<Menu.Item className="month-item" key={`${index}`}>
{months[index]}
</Menu.Item>
)
}
const month = value.month()
const year = value.year()
const options = []
for (let i = year - 10; i < year + 10; i += 1) {
options.push(
<Menu.Item key={i} value={i} className="year-item">
{i}
</Menu.Item>
)
}
const menu = (
<Menu
size="small"
onClick={newYear => {
const now = value.clone().year(newYear.key)
onChange(now)
}}
className="my_calendar_menu"
>
{options}
</Menu>
)
const menu2 = (
<Menu
size="small"
onClick={selectedMonth => {
const newValue = value.clone()
newValue.month(parseInt(selectedMonth.key, 10))
onChange(newValue)
}}
className="my_calendar_menu"
>
{monthOptions}
</Menu>
)
return (
<div style={{ padding: 10 }}>
<Row type="flex" justify="end">
<Col>
<Dropdown size="small" overlay={menu}>
<Button>
{String(year)}
<DownOutlined />
</Button>
</Dropdown>
</Col>
<Col>
<Dropdown size="small" overlay={menu2}>
<Button style={{ marginLeft: 10 }}>
{months[month]}
<DownOutlined />
</Button>
</Dropdown>
</Col>
</Row>
</div>
)
}}
fullscreen={false}
className="calendar"
dateFullCellRender={date => {
let de = moment(date).format(dateFormat)
let cls = ''
if (values && values.indexOf(de) !== -1) {
cls = 'ant-fullcalendar-selected-day'
} else {
cls = ''
}
return (
<div
className={cls}
onClick={() => {
handleSelect && handleSelect(moment(date).format(dateFormat))
}}
>
<div className="ant-fullcalendar-value" style={{ textAlign: 'center' }}>
{moment(date).date()}
</div>
</div>
)
}}
{...resProps}
/>
</Card>
)
}
使用
javascript
// 引入 CalendarPage 组件
import CalendarPage from './CalendarPage'
<Select
dropdownRender={() => (
<CalendarPage
handleSelect={e=>{
// 逻辑处理,动态设置values
}
values={['2023-06-01', '2023-06-25']}
/>
)}
/>