需求
最近想在表单里面实现一个可以联动校验的日期选择框,但是查找了好多博客,没有发现符合的描述,大概是我的需求太简单了,大佬都不屑于记录,本文用于我自己的学习记录,便于以后再次实现。具体的需求大概如下图所示:
逻辑
逻辑是这样的:
- 如果直接点击保存,表单校验,会提示 xxx字段是必填项 ;
- 控件是时间选择器,规定后面的时间不可以早于前面的时间,有相应的提示;
- 如果先选择了后面的字段,提示 请先填写xxx字段,比如:先选择需求,会提示请先填写启动时间;
- 监控前面的字段,如果填写了,清除步骤3中的提示信息,比如:选择了启动时间,清除掉需求字段下面的请先填写启动时间提示。
实现
这个功能的实现主要依赖于Ant里面的一个属性值,没有仔细阅读文档,本来挺简单的操作,结果走了好多弯路。
主要使用的是FormModel里面的clearValidate方法,想法是如果我校验了启动字段,且 需求 字段的时间小于 启动时间 ,那么移除 需求 字段的校验结果。
代码如下(拿出3个字段举例,最后一个和第三个字段验证方法一样):
- 表单代码
<template>
<div>
<a-form-model-item label="启动" prop="startUp">
<a-date-picker v-model="form.startUp" :defaultValue="form.startUp"/>
</a-form-model-item>
<!-- 需求 -->
<a-form-model-item label="需求" prop="demand">
<a-date-picker v-model="form.demand" :defaultValue="form.demand"/>
</a-form-model-item>
<!-- 开发测试 -->
<a-form-model-item label="开发测试" prop="developmentTest">
<a-date-picker v-model="form.developmentTest" :defaultValue="form.developmentTest"/>
</a-form-model-item>
</div>
</template>
- script代码(script代码比较长,但是重复度比较高)
<script>
// 引入日期处理类库
import moment from "moment";
export default {
data() {
// 验证整体计划-启动时间
let validateStartUp = (rule, value, callback) => {
// 空值判断,项目数据问题所以这么判断,可简化
if ( this.form.startUp == null || this.form.startUp.toString().length == 0 ) {
callback(new Error("请填写启动时间"));
}
// 重头戏,移除指定的控件校验,demand就是上面prop定义的
if (this.form.startUp < this.form.demand) {
this.$refs.ruleForm.clearValidate("demand");
callback();
}
// 自定义校验函数时必须返回,这样返回就是校验通过的意思,如果不写,不会有任何提示,但是保存会不通过
callback();
};
// 验证整体计划-需求时间
let validateDemand = (rule, value, callback) => {
// 这里使用了简化的判空方法,利用moment来转换日期的格式,不然比较大小会出现问题
var time1 = moment(this.form.demand).format("YYYY-MM-DD");
var time2 = moment(this.form.startUp).format("YYYY-MM-DD");
var time3 = moment(this.form.developmentTest).format("YYYY-MM-DD");
// alert(time2);
// 验证是否填写了需求时间
if (time1 == "Invalid date") {
callback(new Error("请填写需求时间"));
}
// 验证是否填写了启动时间
if (time2 == "Invalid date") {
callback(new Error("请先填写启动时间"));
}
// 验证时间的先后
if (time1 <= time2) {
callback(new Error("需求时间应晚于启动时间"));
}
// 和上面一样,如果符合规则,移除需求字段的校验结果
if (time1 < time3) {
this.$refs.ruleForm.clearValidate("developmentTest");
callback();
}
callback();
};
// 验证整体计划-开发测试时间(逻辑和上面差不多,不再写注释了)
let validateDevelopmentTest = (rule, value, callback) => {
var time1 = moment(this.form.developmentTest).format("YYYY-MM-DD");
var time2 = moment(this.form.demand).format("YYYY-MM-DD");
var time3 = moment(this.form.goOnline).format("YYYY-MM-DD");
if (time1 == "Invalid date") {
callback(new Error("请填写开发测试时间"));
}
if (time2 == "Invalid date") {
callback(new Error("请先填写需求时间"));
}
if (time1 <= time2) {
callback(new Error("开发测试时间应晚于需求时间"));
}
if (time1 < time3) {
this.$refs.ruleForm.clearValidate("goOnline");
callback();
}
callback();
};
return {
// 表单字段(对应4个日期选择器)
form: {
startUp: "",
demand: "",
developmentTest: "",
goOnline: "",
},
// 表单验证规则
rules: {
startUp: [
{ required: true, validator: validateStartUp, trigger: "change" },
],
demand: [
{ required: true, validator: validateDemand, trigger: "change" },
],
developmentTest: [
{ required: true, validator: validateDevelopmentTest, trigger: "change" },
],
goOnline: [
{ required: true, validator: validateGoOnline, trigger: "change" },
],
},
};
},
methods: {
// 日期转换
moment,
},
};
</script>
多说一句
是我自己太菜,不知道别人是怎么实现的,上面的校验还是不完美,在实现过程中试过使用validateStatus和help来帮助实现,但是效果不太理想,状态是变了,但是提示信息变成灰色的了,并没有移除。
其次,在比较时间的时候也出了问题,简直是一步一个坎,磕磕绊绊的,如果不使用moment转化,直接去比较大小,有的时候选择一样的日期校验会通过,第一次保存之后再次点击保存会提示时间的错误,xxx不应该早于xxx,我猜测是可能是时间戳的问题,第一次选择的时候会有时分秒,第一次保存之后会只有日期,然后再次保存,校验会不通过,这个有待验证。希望这篇博客可以帮助到有需要的人,有好的校验方法也请大家不吝赐教!