iview DatePicker组件带的校验问题(validate方法无法进入)

具体问题具体分析,关于DatePicker的结论请直达结论

 

问题描述

场景

根据业务需求,存在这样一个表单,初始从接口中获取数据,通过Object.assign为字段赋值,编辑表单可以提交;在页面中存在删除子项的操作,该操作会重新调用接口进行赋值

问题

正常提交时,表单正常校验,进入validate的回调函数;但执行删除操作后,无法进入validate回调函数,但可以发现表单触发了校验。

问题排查

业务场景本身并不复杂,因此将排查重心放在校验相关代码,最开始以为是自定义校验方法的问题(自定义校验必须要有callback返回),检查后发现和此无关。

之后考虑可能是表单某个字段的问题,在逐个试验后,最后确定是一个日期字段 basj (备案时间)导致的,此处使用了DatePicker组件,通过v-modal双向绑定进行赋值。

检查后发现,初始化数据后提交,该字段为日期格式;而在删除操作后,重新赋值再进行提交,该字段则变成了字符串。由此联想到刚开始时,在提交表单时,bssj校验不通过,总是提示请选择时间,后来增加了type:"date"才得以解决。

basj: [
    { required: true,type:"date", message: "请选择备案时间", trigger: "change" },
],

这么做的原因就是DatePicker组件使用v-modal后,得到的是时间格式,String类型自然无法校验;那么问题又来了,为什么删除操作之后,日期就变成了字符串类型呢。

分析

对于表单而言,删除操作和直接提交唯一的区别在于重新赋值,如果没有对bssj进行重新赋值,则不存在该问题;而在接口的返回中,bssj是字符串格式,即'2021-05-01 00:00:00';初始化时,变为了日期格式,因此可以确定,DatePicker会自动将字符串格式转化为日期格式;而重新赋值后,变成了字符串,此时可以大胆的猜测,重新赋值时,DatePicker不会再进行转换。根据猜想进行如下实验,先赋初始值,再重新赋值,观察初始值和新值的变化

    // this.formItem.basj = null // 赋值后:日期格式
    // this.formItem.basj = new Date() // 赋值后:日期格式
    // this.formItem.basj = new Date( '2021-05-01 00:00:00') // 赋值后:字符串
    // this.formItem.basj = '2021-05-01 00:00:00' // 赋值后:字符串
    this.formItem.basj = '2021-05-02 00:00:00' // 赋值后:日期格式

    // 获取格式化后的时间
    setTimeout(() => {
      console.log("start------" + this.formItem.basj)
    }, 100);

    // 重新赋值
    setTimeout(() => {
      this.formItem.basj = '2021-05-01 00:00:00'
    }, 200);

    // 获取赋值后的时间
    setTimeout(() => {
      console.log("end------" + this.formItem.basj)
    }, 300);

结论

对于DatePicker组件

  1. 通过v-modal赋值字符串时,会自动转换为时间类型
  2. 当新值为字符串时,且新值与原值为同一时间,则保留字符串

其它

  • 对于该问题的解决方案,在赋值时,手动将字符串转化为时间类型即可。
  • 对于validate,设置了type:"date",但对于String类型,既没有提示,也没有报错,而是一直loading的问题,可能是async-validate的Bug,如果有清楚的同学可以解答一二。
  • 以上结论是实验推论而得,这里附上iview中DatePicker,格式化日期的源码,大家可以自行研究
    parseDate(val) {
        const isRange = this.type.includes('range');
        const type = this.type;
        const parser = (
            TYPE_VALUE_RESOLVER_MAP[type] ||
            TYPE_VALUE_RESOLVER_MAP['default']
        ).parser;
        const format = this.format || DEFAULT_FORMATS[type];
        const multipleParser = TYPE_VALUE_RESOLVER_MAP['multiple'].parser;

        if (val && type === 'time' && !(val instanceof Date)) {
            val = parser(val, format, this.separator);
        } else if (this.multiple && val) {
            val = multipleParser(val, format, this.separator);
        } else if (isRange) {
            if (!val){
                val = [null, null];
            } else {
                if (typeof val === 'string') {
                    val = parser(val, format, this.separator);
                } else if (type === 'timerange') {
                    val = parser(val, format, this.separator).map(v => v || '');
                } else {
                    const [start, end] = val;
                    if (start instanceof Date && end instanceof Date){
                        val = val.map(date => new Date(date));
                    } else if (typeof start === 'string' && typeof end === 'string'){
                        val = parser(val.join(this.separator), format, this.separator);
                    } else if (!start || !end){
                        val = [null, null];
                    }
                }
            }
        } else if (typeof val === 'string' && type.indexOf('time') !== 0){
            val = parser(val, format) || null;
        }

        return (isRange || this.multiple) ? (val || []) : [val];
    },

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值