笔者最近在做一个有关基金管理的后台系统,基于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
完全满足需求。
网友评论