Ant Design的DatePicker组件限制开始结束日期

笔者最近在做一个有关基金管理的后台系统,基于React开发,UI框架选择了当下热门的阿里蚂蚁金服开源框架antd。前两天接到这么一个需求:展现给用户的日期面板,不管用户先选择开始时间还是结束日期,所选日期都不能超过当前的日期,最大日期只能选择今天,未来的日期要禁止选择;同时用户选择的开始日期和结束日期之差最多是30个自然日。看了看需求,只有使用两个DatePicker组件相互之间约束对方,才能达到需求,antd也确实给咱们提供了这样的示例:

//使用两个DatePicker组件
<DatePicker
    disabledDate={this.disabledStartDate}
    format="YYYY-MM-DD HH:mm:ss"
    value={startValue}
    placeholder="请选择开始日期"
    onChange={this.onStartChange}
    onOpenChange={this.handleStartOpenChange}
    showTime
/>
 <DatePicker
    disabledDate={this.disabledEndDate}
    format="YYYY-MM-DD HH:mm:ss"
    value={endValue}
    placeholder="请选择结束始日期"
    onChange={this.onEndChange}
    open={endOpen}
    onOpenChange={this.handleEndOpenChange}
    showTime
 />

为了节省篇幅,每个DatePicker组件对应的方法都是官方文档上的方法,刷新浏览器会点击时间面板并选择时间:


初始化状态.png

官方自带的案例界面,是需要在用户点击时间后再点击确认才会选择时间并将时间面板弹回,而且时间格式默认显示到时分秒,以及今天的定制按钮等更加人性化的界面,在一般项目里其实都不需要,这里我们将其配置项更改为更符合项目要求的界面。
时间精确到年月日即可,去除界面最下方的此刻、选择时间等:

//修改显示日期格式
format="YYYY-MM-DD HH:mm:ss" 
//改为:
format="YYYY-MM-DD" 
//去掉‘此刻选项’,增加showToday配置项,默认true,改为false
showToday={false}
//去掉‘选择时间’,确定按钮删除showTime配置项即可

变成了下面这样:
修改配置项.png

在这里笔者需要告诉读者,限制用户选择时间的方法是disabledDate这个配置项对应的方法,怎么证明呢?可以从文档的源码中寻找到,也可以在disabledDate这个配置项中对应的方法里调试得到验证:

disabledEndDate = (endValue) => {
    console.log('打开结束时间面板啦.....');
    const startValue = this.state.startValue;
    if (!endValue || !startValue) {
      return false;
    }
    return endValue.valueOf() <= startValue.valueOf();
  }

输出结果为:


方法检验.png

以开始时间为例,我们详细解读一下disabledDate这个配置项对应方法里面的代码:

//首先打开时间面板,此方法被调用
disabledStartDate = (startValue) => {
    const endValue = this.state.endValue;//获取结束时间
    if (!startValue || !endValue) {//如果开始日期或者结束日期都没有选择,进入到if判断中
      //在这里直接反回了false,结合页面打开时间面板时,用户时可以任意选择时间这一现象,初步推断出
      //返回false时用户可以自由选择时间,为了验证我们的猜测,把他改为true试试
      return false;
    }
    //(2)startValue.valueOf()获取到的是一个时间戳,符合这个式子的时间,全部不能被选中(返回true),不符合才会被选中(返回false)
    //这句代码的意思就是,如果用户选择了结束时间,则开始的时间一定要小于结束的时间,这也符合生活中的逻辑,开始不能大于结束
    return startValue.valueOf() > endValue.valueOf();
  }

下面的截图是返回为true是打开的时间面板:


验证推测.png

时间面板中的所有时间均不能进行选择,由此可以知道,在disabledDate这个配置项对应的方法中,如果返回的是false,则可以选择时间,返回true则无法对时间进行选择,这一结论至关重要。带着这一结论,再回到代码中对if之外的return进行分析,代码中的(2)。
读完了(2)之后,咱们再继续谈笔者这个需求的事情,需求要开始时间和结束时间不能超过今天,而且结束日期和开始日期之差要在30个自然日之间,当然了,开始日期也不能大于结束日期。则改造disabledDate调用的方法:

disabledStartDate = (startValue) => {//打开开始时间面板调用的函数
    const endValue = this.state.endValue;
    if (!startValue || !endValue) {
        //如果没有选择结束日期,则选择开始日期时,开始日期不能大于今天
        return startValue.valueOf() > new Date().getTime();//大于今天的日期一律返回true,禁止选择
    }
    return startValue.valueOf() > endValue.valueOf();
  }

  disabledEndDate = (endValue) => {//打开结束时间面板调用的函数
    const startValue = this.state.startValue;
    if (!endValue || !startValue) {
      ////如果没有选择开始日期,则结束日期时大于今天
      return endValue.valueOf() > new Date().getTime();//大于今天的日期一律返回true,禁止选择
    }
    return endValue.valueOf() <= startValue.valueOf();
  }

结果:


限制今天之后的时间不能进行选择.png

继续限制结束日期和开始日期之差不能大于30个自然日:

disabledStartDate = (startValue) => {
    const endValue = this.state.endValue;
    if (!startValue || !endValue) {
      //如果没有选择结束日期,则选择开始日期时,开始日期不能大于今天
      return startValue.valueOf() > new Date().getTime();//大于今天的日期一律返回true,禁止选择
    }
    //如果选择了结束日期,则结束日期和开始日期之差大于30天(24*60*60*1000*30是30天的毫秒数),还需要开始日期小于结束日期,返回true,禁止选择
    return endValue.valueOf() - startValue.valueOf() > 24*60*60*1000*30 || endValue.valueOf() <= startValue.valueOf();
  }

  disabledEndDate = (endValue) => {
    const startValue = this.state.startValue;
    if (!endValue || !startValue) {
      ////如果没有选择开始日期,则结束日期时大于今天
      return endValue.valueOf() > new Date().getTime();//大于今天的日期一律返回true,禁止选择
    }
    //结束日期这里稍微复杂了一些,如果选择了开始日期,则结束日期和开始日期除了不能超过30个自然日之外,还需要结束日期不能小于开始日期,还需要不能超过今天,返回true为不能选择,所以用或链接,式子之间的符号正好与咱们分析的相反
    return endValue.valueOf() <= startValue.valueOf() || endValue.valueOf() > new Date().getTime() || endValue.valueOf() - startValue.valueOf() > 24*60*60*1000*30;
  }

结果:
假如开始时间选择了今天(2019-01-09),则结束时间只能选择今天:


开始日期是今天(2019-01-09).png

假如结束日期选择了今天(2019-01-09),则开始日期只能往前推30个自然日:


先选择结束时间.png

假如结束时间与开始时间之差小于30个自然日:
开始日期与结束日期之差小于30个自然日.png

完全满足需求。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容