前言
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情 >>
问题
最近工作中需要优化一个日/月时间范围选择模块,将原先的无限制日期范围选择,修改为选择日期的时候,将日期限定在90天以内,也就是说当你优先选择结束日期时,往前推90天,当你优先选择开始时间时,往后推90天。当选择月份的时候,同理往前推2个月和向后推两个月。如图:
日
- 优先选择开始日期(8.1-10.30)
- 优先选择结束日期(5.9-8.7)
月
- 优先选择开始月份(1-3)
- 优先选择结束月份(4-6)
实现过程
先将官网的案例复制过来,具体地址-->Antd-DatePicker-选择不超过七天的范围
然后针对自己项目中的范围规则进行修改
- 待选日期发生变化的回调的值,获得的值是一个数组,下标为0的则是开始时间,下标为1的则是结束时间
const [dates, setDates] = useState(null);
- 设置空值
const [hackValue, setHackValue] = useState(null);
- 获取到的日期的值
const [value, setValue] = useState(null);
- 不可选择的日期
const disabledDate = (current) => {
if (!dates) {
return false; // 开始和结束日期都未选则所有日期都可选
}
// 如果优先选择开始日期,根据当前为日期表还是月份表,利用monent的diff计算可选日期和开始时间的差值,返回boolean类型
const tooLate = dates[0] && (
form.getFieldValue('dateType') === 'month'
? current.diff(dates[0], 'months') > 1
: current.diff(dates[0], 'days') > 90
)
// 如果优先选择结束日期,同样根据当前为日期表还是月份表,利用monent的diff计算可选日期和开始时间的差值,返回boolean类型
const tooEarly = dates[1] && (
form.getFieldValue('dateType') === 'month'
? dates[1] && dates[1].diff(current, 'month') > 1
: dates[1] && dates[1].diff(current, 'days') > 90
)
return !!tooEarly || !!tooLate;
};
- 弹出日历和关闭日历的回调
const onOpenChange = (open) => { // open为boolean值,为true时则日历打开,false则日历关闭
if (open) {
// 因为本身需要有默认值,所以重新打开日历时需要先将默认值清空
form.setFieldsValue({
date: null
});
setHackValue([null, null]);
setDates([null, null]);
} else {
setHackValue(null);
}
};
- 默认值,为月份时默认展示前6个月,为日期是展示近10天
const showMonth = [moment(new Date()).subtract(6, 'months'), moment(new Date())]
const showDate = [moment(new Date()).subtract(10, 'days'), moment(new Date())]
- RangePicker组件属性
<Form.Item
label="统计时间"
name="date"
initialValue={form.getFieldValue('dateType') === 'month' ? showMonth : showDate}
>
<RangePicker
allowClear // 是否可清除
value={hackValue || value} // 获取选择的日期
disabledDate={disabledDate} // 不可选择的日期
onOpenChange={onOpenChange} // 弹出日历和关闭日历的回调
onChange={val => setValue(val)} // 时间发生变化的回调
onCalendarChange={val => setDates(val)} // 待选日期发生变化的回调
picker={form.getFieldValue('dateType') === 'month' ? 'month' : 'date'}
getPopupContainer={(triggerNode: { parentNode: any; }) => triggerNode.parentNode} // 控制弹出框不随页面滚动而滚动
/>
</Form.Item>
- radio组控制日历为日期还是月份
const changeDateType = (e: any) => {
form.setFieldsValue({
date: e.target.value === 'month' ? showMonth : showDate
});
};
<Form.Item name="dateType" initialValue='date'>
<Radio.Group onChange={changeDateType}>
<Radio value="date">按日</Radio>
<Radio value="month">按月</Radio>
</Radio.Group>
</Form.Item>
总结
这里主要是设定的默认值没有及时清空,导致每次打开日历,在月份进行计算的时候始终会有bug,一直以为是moment的diff算法有问题,这个算法在进行向前或者向后推三个月是大于1目前还在了解,后面了解到再做补充,有知情的大佬可以评论区留言,谢谢。