Antd使用日期RangePicker框,实现左侧有时间区间选择 本月、上月、过去7天、过去30天等

产品要求:在原有日期框的左侧,添加本月、上月、过去7天、过去30天等选项。

 看Antd组件RangePicker:

 只存在底下的选择

<RangePicker
  ranges={{
    '今天': [moment(), moment()],
    '本月': [moment().startOf('month'), moment().endOf('month')],
    '过去7天': [moment().subtract(7, 'day').endOf('day'), moment().endOf('month')],
  }}
  onChange={onChange}
  dropdownClassName='custom' //样式 引入
/>

采用CSS去改变样式 达到左侧展示的需求

:global {
  .ant-calendar-panel {
    display: flex;
  }
}
效果:

在详细的去控制一下元素样式属性:
记得给到RangePicker的dropdownClassName属性
:global {
  .ant-calendar-panel {
    display: flex;
    flex-direction: row-reverse;

    .ant-calendar-footer {
      padding: 0px;
      border-right: 1px solid #E8E8E8;

      .ant-calendar-footer-btn {
        .ant-tag-blue {
          color: #000;
          background: #fff;
          background-color: "#fff";
          display: block;
          border: 0px;
          height: 35px;
          width: 100%;
          cursor: pointer;
        }
      }
    }
  }
}

达到需求:

产品为什么会这样提?

因为产品从别人系统看到这种交互,查了一下别的组件库  ElementUI是一样的 而Antd3x中这种预设范围都是在下方的

所以会出现需要二次封装时间框修改一部分样式 
<think>我们参考了引用中的代码片段,特别是引用[3]中关于禁用日期实现方式。用户的需求是:在Ant Design 4.x的RangePicker组件中,设置只能选择5内的日期(包括今)。 实现思路: 1. 使用`disabledDate`属性来动态禁用不在5范围内的日期。 2. 计算5前的日期(作为可选开始的最小日期)和5后的日期(作为可选结束的最大日期)是不合适的,因为需求是“只能选择5内”,即任意选择的起始日期和结束日期之间的跨度不能超过5,且选择日期范围必须在某个时间区间内?还是说只能选择从今起往后5? 但是,用户的问题描述是“设置日期只能选择5内”,通常有两种理解: a) 只能选择以及未来4(共5)的日期范围(即从今到未来4)。 b) 任意选择一个时间段,但这个时间段不能超过5,并且这个时间段必须在某个时间范围内(比如最近5)? 不过,根据引用[3]和[4]的类似需求,我们更常见的是限制选择的时间跨度(即开始和结束之间不超过5)以及限制选择的时间范围(比如只能选择最近5内的日期)。但用户的问题没有明确说明,所以我们考虑两种常见情况: 情况1:限制选择的时间跨度不超过5(即结束日期减开始日期不超过5)。 情况2:限制只能选择某个固定时间段内的5(比如从今起往前5或往后5)。 根据问题中的“只能选择5内”,结合业务中常见的需求(比如只能选择最近5),我们假设用户需要的是: - 可以任意选择日期,但选择日期范围必须在5之内(跨度不超过5),并且这个日期范围不能超出某个时间段(比如不能选择5前的日期,只能选择和未来4?)但是,问题没有明确是过去还是未来。 然而,从引用[1]中可以看到,业务中常常需要设置“最近一周”、“最近一个月”等,这些是过去的时间段。所以用户可能想限制只能选择最近5(包括今,即今以及前4)的日期。 因此,我们按照两种需求分别给出方案: 需求A:限制只能选择从今起往前5(最近5)内的日期(包括今),也就是说,只能选择从5前到今这个时间段内的日期,并且可以选择这个时间段内的任意连续日期(不需要跨度正好5,只要在这个时间段内即可)。 需求B:限制选择日期跨度不超过5(即开始和结束之间最多5),但不限制具体的开始和结束日期(可以是任意日期,只要跨度不超过5)。 由于用户的问题描述是“设置日期只能选择5内”,结合引用[3]和[4]的上下文,我们更倾向于需求A:限制日期在最近5内(即只能选择过去5到今)。 下面分别给出两种需求的实现: 需求A:只能选择最近5(从今起往前5)内的日期(包括今) 可选范围:从5前(包含)到今(包含) 需求B:选择的时间跨度不超过5,但不限制在某个固定时间段。 根据引用[3]的示例,我们使用`disabledDate`函数来实现。 我们先实现需求A: 步骤: 1. 计算5前的日期(00:00:00) 2. 禁用所有小于5日期和大于今日期 代码示例: ```jsx import { DatePicker } from 'antd'; import moment from 'moment'; const { RangePicker } = DatePicker; // 在组件中使用 <RangePicker disabledDate={(current) => { // 如果没有选择任何日期,则禁用5前之前和今之后的所有日期 const startOfToday = moment().startOf('day'); const fiveDaysAgo = moment().subtract(5, 'days').startOf('day'); // 如果当前日期在5前之前(即小于5前)或者在今之后(即大于今),则禁用 return current && (current < fiveDaysAgo || current > startOfToday); }} /> ``` 注意:这样设置后,用户只能选择从5前到今之间的日期,并且这个范围内的任意连续日期段都可以选择(可以只选1,也可以选连续的2,最多5)。 但是,这样设置后,用户可以选择的最大跨度就是5(因为5前到今是5)。所以这个已经满足了需求A。 需求B:限制选择的时间跨度不超过5(即结束日期减开始日期不超过5),同时我们可能还要限制不能选择未来的日期(根据业务,如果需要的话)?这里我们只限制跨度。 实现需求B的思路: 我们需要在用户选择了一个开始日期后,动态计算5后的日期,然后禁用这个日期范围之外的日期。但是,由于是RangePicker,我们需要在`disabledDate`函数中根据当前选择的开始日期(如果有)来动态禁用。 但是,antdRangePicker的`disabledDate`函数只接收当前日期作为参数,我们需要通过外部状态来记录选择的开始日期(如果有)。不过,antd提供了`onCalendarChange`事件,我们可以通过它来记录当前选择的开始日期(当用户选择第一个日期后)。 具体实现: 1. 使用状态`startValue`和`endValue`来记录当前选择的开始和结束日期(注意:这些状态是用户选择过程中日历面板上的临时值,不是最终确认的值)。 2. 在`disabledDate`函数中,根据`startValue`是否存在来动态禁用: - 如果没有选择开始日期,则不禁用任何日期(或者根据业务需要设置其他禁用规则,比如不能选择未来的日期?) - 如果选择了开始日期,那么我们需要限制只能选择从开始日期往后5内的日期(同时,也要限制开始日期之前的日期?通常我们会禁用开始日期之前的日期,因为结束日期不能早于开始日期,这是默认行为,但跨度限制我们主要限制结束日期不能超过开始日期5) 代码示例: ```jsx import React, { useState } from 'react'; import { DatePicker } from 'antd'; import moment from 'moment'; const { RangePicker } = DatePicker; const MyRangePicker = () => { const [startValue, setStartValue] = useState(null); const [endValue, setEndValue] = useState(null); const disabledDate = (current) => { if (!startValue) { // 如果没有选择开始日期,我们可以选择不禁用,或者根据业务需要禁用一些日期(比如禁用未来的日期) // 这里我们不禁用,仅限制跨度 return current && current > moment().endOf('day'); // 例如:禁用今之后的日期,如果需要可以加上 } // 计算开始日期5后的日期 const maxDate = moment(startValue).add(5, 'days'); const minDate = moment(startValue).subtract(5, 'days'); // 这里我们限制:结束日期只能在开始日期的前后5内?但是通常我们只允许结束日期在开始日期之后,所以主要限制结束日期不能超过开始日期5 // 同时,我们也要限制结束日期不能早于开始日期(但默认antd会处理结束日期早于开始日期的情况,所以这里主要防止超过5) // 但是注意:disabledDate函数会应用于两个面板,所以我们需要同时限制开始面板和结束面板。 // 然而,在选择了开始日期后,结束面板应该禁用开始日期之前的日期,以及开始日期+5之后的日期。 // 由于RangePicker的disabledDate会同时影响开始和结束面板,所以我们需要区分当前日期是在选择开始还是结束面板? // 遗憾的是,在disabledDate函数中我们无法知道当前是哪个面板,因此我们需要额外的状态来记录当前激活的面板(antd 4.21.0+支持`onPanelChange`可以记录激活的面板,但这里为了简单,我们采用另一种方式) // 另一种思路:无论当前是开始面板还是结束面板,我们都做如下限制: // - 如果当前日期在开始日期的5之前,则禁用(因为结束日期不能早于开始日期,所以开始面板不需要考虑这个禁用,但为了统一,我们这样写) // - 或者当前日期在开始日期的5之后,则禁用 // 但是这样写,在选择开始日期时,用户就不能选择超过5范围外的日期了?这不符合需求B的初衷,因为需求B是任意选择一个开始日期,然后结束日期不能超过开始日期5。 // 所以我们需要分开处理:当选择开始日期时,我们希望可以任意选择开始日期(只要不禁用),然后结束日期受到开始日期的限制。因此,在开始日期选择时,我们不禁用任何日期(除了可能的基本限制),在选择了开始日期后,我们禁用超出开始日期5日期。 // 但是,这样会有一个问题:当用户先选择了开始日期,然后想改变开始日期(此时结束日期还未选),我们希望开始日期选择不受限制(因为还没有形成范围)。因此,我们需要在disabledDate中判断当前是选择开始还是结束?但antd没有提供这个信息。 // 因此,我们采用另一种方法:使用两个状态记录当前两个输入的激活状态(通过`onFocus`和`onBlur`),但这样比较复杂。 // 更简单的方法是:我们不在开始面板上做额外限制(除了基本限制),只限制结束面板。但是,当用户重新选择开始日期时,我们希望结束日期的限制是基于新的开始日期?所以我们需要在开始日期改变时,重新计算结束日期的可选范围。 // 实际上,antd官方提供了一个例子:https://ant.design/components/date-picker-cn/#components-date-picker-demo-select-in-range // 这个例子中,通过记录hover日期来优化用户体验,但这里我们只需要简单的跨度限制。 // 我们参考官方例子,实现如下: if (!startValue) { return false; // 这里不禁用 } // 限制结束面板:只能选择开始日期前后5内?不,我们要求结束日期在开始日期之后,且不超过5 // 但是,当用户选择开始日期时,我们希望开始面板上所有日期都是可选的(除了基本禁用规则),所以我们需要区分当前是选择开始还是结束面板?我们可以借助`onCalendarChange`事件来记录当前激活的面板。 // 由于比较复杂,这里我们采用一个折中方案:在选择了开始日期后,禁用所有超过开始日期5以外的日期(不管是在开始面板还是结束面板),这样用户重新选择开始日期时,也只能选择在原来结束日期5内的日期?这并不理想。 // 因此,我们更推荐使用需求A的方案,或者使用antd官方示例中“选择范围”的例子(限制跨度为5)。 }; // 所以,我们参考官方示例,使用`onCalendarChange`和`disabledDate`结合,并记录开始日期和结束日期。 // 具体做法如下(官方示例): const onCalendarChange = (dates, dateStrings, info) => { // 当用户选择开始日期时,触发 // info.range 表示是哪个面板?'start'或'end',但实际上antd 4.x的onCalendarChange的info可能没有range,我们可以通过dates数组来判断 // dates[0]是开始日期,dates[1]是结束日期 // 当用户点击第一个输入时,会先清空dates,然后选择第一个日期,此时dates[0]有值,dates[1]为null // 然后用户再点击第二个输入选择第二个日期 // 所以我们可以通过dates数组来设置startValue和endValue setStartValue(dates[0]); setEndValue(dates[1]); }; // 修改disabledDate函数 const disabledDate2 = (current) => { if (!startValue) { // 如果没有选择开始日期,可以设置基本规则(比如禁用未来的日期),这里我们假设业务上只能选择及之前的日期 return current > moment().endOf('day'); } // 计算与开始日期的差距 const diffDays = Math.abs(current.diff(startValue, 'days')); // 如果当前日期在开始日期的5之外,则禁用 return diffDays > 5; }; // 但是这样写会禁用掉所有与开始日期相差超过5日期,不管是之前还是之后。而通常我们要求结束日期在开始日期之后不超过5,开始日期之前的不需要禁用?不对,因为我们要求跨度不超过5,所以结束日期可以早于开始日期吗?不可以,RangePicker要求结束日期大于等于开始日期。 // 所以,我们应该: // - 当选择结束日期时,只能选择开始日期到开始日期+5之间的日期。 // - 当选择开始日期时,只能选择结束日期-5到结束日期之间的日期(如果有结束日期)。但是,我们这里没有结束日期,因为我们是先选开始再选结束。 // 因此,我们分开处理: // - 如果当前面板是结束面板,那么禁用不在[startValue, startValue+5]的日期 // - 如果当前面板是开始面板,那么禁用不在[endValue-5, endValue]的日期(如果有结束日期) // 但是,我们如何知道当前面板是开始还是结束?在disabledDate函数中无法直接得知。 // 所以,我们使用官方示例的方法:https://ant.design/components/date-picker-cn/#components-date-picker-demo-select-in-range // 官方示例通过记录hover日期来优化,我们这里只做最简单的:当有开始日期时,结束面板的禁用规则是:小于开始日期或者大于开始日期+5日期被禁用。 // 但我们无法区分面板,所以只能统一处理:在选择了开始日期后,我们禁用开始日期5范围外的日期(包括开始日期之前的日期,因为结束日期不能早于开始日期,所以开始日期之前的日期本就应该禁用,除了在开始面板上选择新的开始日期时)。这样,当用户重新选择开始日期时,他只能选择当前结束日期(如果有)5范围内的日期?这也不对,因为当前结束日期可能为空。 // 考虑到实现的复杂性,以及用户可能更倾向于需求A,我们这里先给出需求A的实现。如果用户的需求是跨度不超过5,那么我们可以参考antd官方示例中的“限制日期范围”例子(使用disabledDate动态计算)。 // 根据官方示例,我们这样实现需求B(限制跨度不超过5): const disabledDate3 = (current) => { if (!startValue && !endValue) { // 两个都没选,可以设置基本规则,比如禁用未来的日期 return current > moment().endOf('day'); } // 如果开始日期有值,结束日期为空(正在选择结束日期) if (startValue && !endValue) { // 只能选择开始日期到开始日期+5之间的日期 const maxDate = moment(startValue).add(5, 'days'); const minDate = moment(startValue).subtract(5, 'days'); // 但是,我们要求结束日期不能早于开始日期,所以结束日期面板上,开始日期之前的日期应该禁用(这个antd默认会做,但我们这里要额外限制不能超过5) return current < startValue.startOf('day') || current > maxDate.endOf('day'); } // 如果结束日期有值,开始日期为空(这种情况不会出现,因为我们是先选开始再选结束)或者两个都有值(重新选择开始日期时) if (endValue) { // 当重新选择开始日期时,开始日期不能大于结束日期,并且开始日期必须在结束日期的5范围内 const maxDate = moment(endValue).add(5, 'days'); const minDate = moment(endValue).subtract(5, 'days'); return current < minDate.endOf('day') || current > maxDate.endOf('day') || current > moment().endOf('day'); } return false; }; // 但是,这样写仍然不完美,因为antdRangePicker选择开始日期后会立即弹出结束面板,所以开始日期设置后,结束面板上的日期会被限制。但是当我们重新点击开始面板时,开始面板上的日期并没有受到结束日期的限制(因为我们没有记录结束日期,并且结束日期可能还没选)。 // 因此,我们推荐使用需求A的方案,或者使用官方示例的完整实现:https://ant.design/components/date-picker-cn/#components-date-picker-demo-select-in-range // 由于完整实现较为复杂,这里不展开,用户可以参考官方示例。 // 综上所述,针对用户的问题,我们给出需求A(限制只能选择最近5内)的实现,因为它更简单且常见。 return ( <RangePicker value={[startValue, endValue]} onCalendarChange={onCalendarChange} disabledDate={disabledDate3} /> ); }; ``` 由于需求B的实现相对复杂,且不是用户明确要求的,我们优先给出需求A的代码。 在需求A中,我们禁用了5前之前和今之后的所有日期,用户只能选择5前到今范围内的日期。 最后,我们假设用户的需求是只能选择最近5(包括今)的日期,所以采用需求A的实现。 因此,最终代码(需求A): ```jsx import { DatePicker } from 'antd'; import moment from 'moment'; const { RangePicker } = DatePicker; // 在组件中直接使用 <RangePicker disabledDate={(current) => { const today = moment().endOf('day'); const fiveDaysAgo = moment().subtract(5, 'days').startOf('day'); // 注意:current是moment对象,并且antd要求返回true表示禁用 return current && (current < fiveDaysAgo || current > today); }} /> ``` 注意:这里我们使用了`startOf('day')`和`endOf('day')`来确保比较的是日期(忽略时间部分)。 另外,如果业务需要设置默认时分秒为00:00:00~23:59:59,可以参考引用[1]中的`showTime`配置。 例如,设置时间选择器并设置默认时间: ```jsx <RangePicker disabledDate={(current) => { const today = moment().endOf('day'); const fiveDaysAgo = moment().subtract(5, 'days').startOf('day'); return current && (current < fiveDaysAgo || current > today); }} showTime={{ hideDisabledOptions: true, defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')], }} /> ``` 这样,用户选择日期后,时间会自动设置为00:00:00和23:59:59。 总结:我们给出了需求A(限制只能选择最近5内)的完整实现代码,并提供了设置默认时间的选项。 如果用户的需求是限制跨度不超过5,那么实现起来更复杂,可以参考antd官方示例进行实现。 相关问题: 1. 如何设置RangePicker只能选择之后的日期? 2. 如何设置RangePicker的默认时间为00:00:00到23:59:59? 3. 如何动态设置RangePicker的可选日期范围? 注意:以上代码基于antd 4.x和moment.js。 </think>基于您提供的引用内容,我将为您详细解答如何在 Ant Design 4.x 中实现 RangePicker 日期范围限制为 5 内的解决方案。 ### 解决方案:限制 RangePicker 只能选择 5 日期 核心方法是使用 `disabledDate` 属性动态禁用不符合条件的日期: ```jsx import { DatePicker } from 'antd'; import moment from 'moment'; const { RangePicker } = DatePicker; // 在组件中使用 <RangePicker disabledDate={(current) => { // 禁用今之后的日期 if (current && current > moment().endOf('day')) { return true; } // 禁用 5 前的日期 const fiveDaysAgo = moment().subtract(5, 'days').startOf('day'); return current && current < fiveDaysAgo; }} /> ``` ### 关键配置解析 1. **`disabledDate` 函数逻辑**: - `current > moment().endOf('day')`:禁用今之后的所有日期 - `current < moment().subtract(5, 'days')`:禁用 5 前的日期(精确到 00:00:00) - 通过 `&&` 连接两个条件,禁用范围外的日期 2. **时间精度控制**: - `startOf('day')` 确保日期从 00:00:00 开始计算 - `endOf('day')` 确保日期截止到 23:59:59 - 使用 `moment` 保证时间计算精度 [^1][^2] 3. **时分秒设置**(可选): ```jsx showTime={{ defaultValue: [ moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss') ] }} ``` ### 完整组件示例 ```jsx import React from 'react'; import { DatePicker } from 'antd'; import moment from 'moment'; export default () => ( <RangePicker format="YYYY-MM-DD HH:mm:ss" disabledDate={(current) => { const todayEnd = moment().endOf('day'); const fiveDaysAgo = moment().subtract(5, 'days').startOf('day'); return current && (current > todayEnd || current < fiveDaysAgo); }} showTime={{ defaultValue: [ moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss') ] }} onChange={(dates) => { if (dates) { console.log('选择范围:', [ dates[0].format('YYYY-MM-DD HH:mm:ss'), dates[1].format('YYYY-MM-DD HH:mm:ss') ]); } }} /> ); ``` ### 注意事项 1. 使用 `moment().subtract(5, 'days')` 计算时间范围时: - 包含今:显示为「今日+前4」 - 不包含今:改为 `moment().subtract(6, 'days')` 2. 日期比较时务必使用 `startOf('day')/endOf('day')` 避免时间戳误差 3. 若需要限制选择跨度不超过 5 (而非绝对范围),需配合 `onCalendarChange` 动态计算 [^3] > 此实现基于 Ant Design 4.x 官方文档和日期限制的最佳实践,通过精确的 moment.js 时间计算确保日期范围控制的准确性 [^2][^4]。 ### 相关问题 1. 如何设置 RangePicker 默认选中最近 5 范围? 2. 如何限制日期选择的最大跨度为 5 (相对范围)? 3. 如何在禁用的日期上显示自定义提示信息? 4. 如何结合 Form 表单验证日期范围限制?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值