项目中使用了蚂蚁的ProComponents组件库,其中依赖antd5.x。
之前有个产品需求是选择日期时间,但是有一个月的范围限制。
我的实现方式如下:
const LIMIT_DAYS = 30
const getYearMonth = (date: Dayjs) =>
date.year() * 12 + date.month()
const disabledDate: DatePickerProps['disabledDate'] = (
current,
{ from, type }
) => {
if (from) {
const minDate = from.add(-(LIMIT_DAYS - 1), 'day')
const maxDate = from.add(LIMIT_DAYS - 1, 'day')
switch (type) {
case 'year':
return (
current.year() < minDate.year() ||
current.year() > maxDate.year()
)
case 'month':
return (
getYearMonth(current) < getYearMonth(minDate) ||
getYearMonth(current) > getYearMonth(maxDate)
)
// 时间的卡控
default:
return Math.abs(current.diff(from, 'day')) >=
LIMIT_DAYS
}
}
return false
}
/**
* 设置disableTime
* @param from: 传入的边界时间
* @param isStartTime: 第一个参数 from 是否是起始时间
* */
const getDisableTime = (
from: Dayjs,
isStartTime = true
) => {
// 找到临界值
const limitTime = isStartTime
? from.add(1, 'second')
: from.subtract(1, 'second')
return {
disabledHours: () => {
const limitHour = limitTime.hour()
return Array.from(
{ length: 24 },
(_, i) => i
).filter((hour) => {
return isStartTime
? hour < limitHour
: hour > limitHour
})
},
disabledMinutes: (selectedHour: number) => {
const limitHour = limitTime.hour()
const limitMinute = limitTime.minute()
if (selectedHour === limitHour) {
return Array.from(
{ length: 60 },
(_, i) => i
).filter((minute) =>
isStartTime
? minute < limitMinute
: minute > limitMinute
)
}
return []
},
disabledSeconds: (
selectedHour: number,
selectedMinute: number
) => {
const limitHour = limitTime.hour()
const limitMinute = limitTime.minute()
const limitSecond = limitTime.second()
if (
selectedHour === limitHour &&
selectedMinute === limitMinute
) {
return Array.from(
{ length: 60 },
(_, i) => i
).filter((second) =>
isStartTime
? second < limitSecond
: second > limitSecond
)
}
return []
},
}
}
// 设置disabledTime 控制选择的时间
const disabledTime: RangePickerProps['disabledTime'] = (
current,
range,
info
) => {
if (info.from) {
const minDate = info.from.add(-LIMIT_DAYS, 'day')
const maxDate = info.from.add(LIMIT_DAYS, 'day')
if (current.isSame(maxDate, 'day')) {
return getDisableTime(info.from, false)
}
if (current.isSame(minDate, 'day')) {
return getDisableTime(info.from, true)
}
}
return {}
}
export default Page() {
return <ProFormDateTimeRangePicker
// xxxx 省略部分熟悉
fieldProps={{
disabledDate,
disabledTime,
showTime: {
hideDisabledOptions: true,
},
}}
/>
}
设置了两个属性disabledDate和disabledTime,其中disableDate限制具体日期的选择,disabledTime限制时间。
disabledDate中内容和官方Demo差不多,只不过我们选的日期(info.from)这里会选择时分秒,
例如:起始时间选择了2024-10-01 02:00:00,时间限制为7天,那结束时间就该是:2024-10-08 01:59:59
起始时间选择了2024-10-01 00:00:00,时间限制为7天,那结束时间就该是:2024-10-07 23:59:59
又上看出,如果选择了时分秒后,日期控制的时间可以多选一天。
const LIMIT_DAYS = 30
const disabledDate: DatePickerProps['disabledDate'] = (
current,
{ from, type }
) => {
if (from) {
// ... 省略部分代码
// 除了日期外,是否还选择了时分秒
const hasSelectHourMinuteSecond =
from.hour() || from.minute() || from.second()
switch (type) {
// ... 省略部分代码
// 时间的卡控
/**
* 起始时间没有选择时分秒
* 2024-10-01 00:00:00 -> 2024-10-30 23:59:59
*
* 起始时间选择了时分秒
* 2024-10-01 01:00:00 -> 2024-10-31 00:59:59
*
* 选择了时分秒后 时间期限默认要多一天
*
*/
default:
return hasSelectHourMinuteSecond
? Math.abs(current.diff(from, 'day')) >
LIMIT_DAYS
: Math.abs(current.diff(from, 'day')) >=
LIMIT_DAYS
}
}
return false
}
disabledTime中我们只要控制住边界中最大的天数和最小的天数对应的时分秒。
例如:
如果我选择了2024-10-08 02:00:00,那么我能选择的最大时间是2024-10-15 01:59:59
我能选择的最小时间是2024-10-01 02:00:01
我们能够选择的最大日期在disabledDate中已经被限制了,这边我们只要判断对应的时分秒就行。
const getDisableTime = (
from: Dayjs,
isStartTime = true
) => {
// 找到临界值
const limitTime = isStartTime
? from.add(1, 'second')
: from.subtract(1, 'second')
// ... 省略
}
isStartTime判断当前选择的时间是否是区间的起始时间,算出limitTime
小时判断很简单,根据判断出来的limitTime, isStartTime来判断即可。
const getDisableTime = (
from: Dayjs,
isStartTime = true
) => {
// 找到临界值
// ...
return {
disabledHours: () => {
const limitHour = limitTime.hour()
return Array.from(
{ length: 24 },
(_, i) => i
).filter((hour) => {
return isStartTime
? hour < limitHour
: hour > limitHour
})
},
}
}
分,秒的计算不能直接判断,我们要判断出当前选择的小时(小时,分钟)
举个🌰:
2024-10-01 02:02:02 - 2024-10-08 02:02:01
日期选择了 2024-10-08 ,此时能选择的小时只有 0,1,2
当小时选择2时,分钟选只有0,1,2
当分钟选择了2时,秒的只能选1。
const getDisableTime = (
from: Dayjs,
isStartTime = true
) => {
// 找到临界值
// ...
return {
// 控制小时
// ...
disabledMinutes: (selectedHour: number) => {
const limitHour = limitTime.hour()
const limitMinute = limitTime.minute()
if (selectedHour === limitHour) {
return Array.from(
{ length: 60 },
(_, i) => i
).filter((minute) =>
isStartTime
? minute < limitMinute
: minute > limitMinute
)
}
return []
},
disabledSeconds: (
selectedHour: number,
selectedMinute: number
) => {
const limitHour = limitTime.hour()
const limitMinute = limitTime.minute()
const limitSecond = limitTime.second()
if (
selectedHour === limitHour &&
selectedMinute === limitMinute
) {
return Array.from(
{ length: 60 },
(_, i) => i
).filter((second) =>
isStartTime
? second < limitSecond
: second > limitSecond
)
}
return []
},
}
}
如果有更好的实现方案,欢迎提出👏👏👏