• antd-vue 2.x 表单验证的坑,你遇到过么


    好多年没有写博客了,突然写一篇。

    最近学习AntdVue2.x+Vue3.x ,据说antdv 特别优秀,更新也及时还适配了vue3,所以,选择了antdv,而不是elementui,虽然elementui也有新版本了,但是总觉得那不是同一套体系了

    在学习到Form表单验证的时候,发现一个问题,来这里吐个槽,看看大家有没有遇到这样的问题。

    问题的起因是,Antdv表单项间距特别高,我想他这是为了可以放错误提示信息,不仅官方文档这样写,提供的pro框架也是这样的,参考了很多的第三方框架也是遵循官方的提示样式,可能大家都觉得这样挺好的,表单项下放置错误提示信息。

    凡事总有个但是,但是我觉得这样不好,间距太高了,提示信息太占位置了,页面比较紧凑时,更是让人难以接受,于是,我想改一下这个显示方式,使用 鼠标悬停气泡显示错误提示信息。

    表单项验证错误时,显示红框,并在后面显示红色的X,再辅助鼠标悬停气泡提示,这样就能够适应绝大多数场景。

    毕竟是学习框架,看着文档发现了这个form事件validate,在每个表单项被验证后会触发事件,我就真的写了,但是他竟然不生效

    我本地不生效,然后还特地写了最小验证环境  CodeSandBox  ,提交到了官方github

    不过,总不能这个事件不生效,就放弃了,如果这是项目要求,总得想办法实现的。经过一天的奋战,总算解决了。

    解决思路如下:

    1、借用验证规则中的自定义验证,所有的规则,不管是用户自定义的验证规则,还是使用已定义的,我都再进行一层包装,包装内,自己调用验证

    2、css调整表单项间距

    3、悬浮气泡提示信息,借用第三方提供的(tippy.js),由于antdv并没有提供方法调用方式的tooltip

    最终实现效果如下:

     核心代码如下:

      1 <template>
      2   <a-form
      3     name="custom-validation"
      4     class="lan-form"
      5     ref="formRef"
      6     :labelCol="{ span: 24 }"
      7     :model="user"
      8     :rules="rules"
      9     :layout="formlayout"
     10     @submit="mySubmit"
     11     @validate="myValidateForm"
     12     @validateField="myValidateFormFields"
     13     @finish="myFinish"
     14     @finishFailed="myFinishFailed"
     15   >
     16     <a-form-item
     17       has-feedback
     18       label="姓名"
     19       name="name"
     20       :labelCol="{ span: 2 }"
     21       :validateFirst="true"
     22       class="name"
     23     >
     24       <a-input v-model:value="user.name" type="text" autocomplete="off" />
     25     </a-form-item>
     26     <a-form-item
     27       has-feedback
     28       label="年龄"
     29       name="age"
     30       :labelCol="{ span: 2 }"
     31       :validateFirst="true"
     32     >
     33       <!-- <a-input-number v-model:value="user.age" class="nohandler"></a-input-number> -->
     34       <a-input v-model:value.number="user.age"></a-input>
     35     </a-form-item>
     36     <a-form-item
     37       has-feedback
     38       label="定量"
     39       name="num"
     40       :labelCol="{ span: 2 }"
     41       :validateFirst="true"
     42     >
     43       <!-- <a-input-number v-model:value="user.age" class="nohandler"></a-input-number> -->
     44       <a-input v-model:value.number="user.num"></a-input>
     45     </a-form-item>
     46     <a-form-item
     47       has-feedback
     48       label="远程"
     49       name="remote"
     50       :labelCol="{ span: 2 }"
     51       :validateFirst="true"
     52     >
     53       <a-input v-model:value.number="user.remote"></a-input>
     54     </a-form-item>
     55     <a-form-item>
     56       <a-button type="primary" html-type="submit" @click="submitForm"
     57         >提交</a-button
     58       >
     59       <a-button type="default" @click="resetForm">重置</a-button>
     60 
     61       <a-button type="default" @click="loadRules">重置</a-button>
     62       <a-button type="default" @click="validate2">重置</a-button>
     63       <a-button type="default" @click="validate3">设置验证</a-button>
     64     </a-form-item>
     65   </a-form>
     66 </template>
     67 <script>
     68 import Schema from "async-validator";
     69 import tippy from "tippy.js";
     70 export default {
     71   name: "App",
     72   data: function () {
     73     return {
     74       user: {
     75         name: "",
     76         age: 0,
     77         num: "",
     78         remote: "",
     79       },
     80       rules: {
     81         name: [
     82           {
     83             required: true,
     84             min: 3,
     85             max: 5,
     86             message: "请输入3——5个字符",
     87           },
     88         ],
     89         age: [
     90           {
     91             type: "number",
     92             min: 3,
     93             max: 5,
     94             message: "只能输入大于3小于5的数字",
     95           },
     96         ],
     97         num: [
     98           {
     99             required: true,
    100             type: "enum",
    101             enum: [5, 6],
    102             message: "输入数字5或者6",
    103           },
    104           {
    105             validator: function (rule, value, callback) {
    106               debugger;
    107               if (value == 5) {
    108                 return callback();
    109               }
    110               return callback("请输入数字5(同步验证)");
    111             },
    112           },
    113         ],
    114         remote: [
    115           {
    116             type: "number",
    117             //异步验证
    118             min: 3,
    119             max: 9,
    120             message: "只能输入大于3小于9的数字",
    121           },
    122           {
    123             type: "number",
    124             asyncValidator: function (rule, value, callback) {
    125               setTimeout(function () {
    126                 if (value == 5) {
    127                   return callback();
    128                 }
    129                 return callback("只能输入数字5(异步验证)");
    130               }, 1000);
    131             },
    132           },
    133         ],
    134       },
    135     };
    136   },
    137   methods: {
    138     validateField: function (
    139       model,
    140       rules,
    141       isFirst,
    142       successCallback,
    143       failCallback,
    144       preCallback
    145     ) {
    146       let validator = new Schema(rules);
    147       let option = isFirst ? { firstFields: true } : {};
    148       return validator
    149         .validate(model, option)
    150         .then(() => {
    151           // 校验通过
    152           successCallback(model);
    153           preCallback();
    154         })
    155         .catch(({ fields, errors }) => {
    156           failCallback(model, errors);
    157           preCallback(errors);
    158         });
    159     },
    160     validateSucessCallback: function (argmodel) {
    161       try {
    162         for (let field in argmodel) {
    163           let formElement = document.getElementById(
    164             "custom-validation_" + field
    165           );
    166           let formitemWrapper =
    167             formElement.parentElement.parentElement.parentElement;
    168           let lanTippy2 = formitemWrapper.lanTippy;
    169           if (lanTippy2) {
    170             lanTippy2.hide();
    171             lanTippy2.disable();
    172           }
    173         }
    174       } catch (e) {
    175         console.error(e);
    176       }
    177     },
    178     validateFailCallback: function (model, errors) {
    179       let errorMessages = "";
    180       for (let { field, message } of errors) {
    181         errorMessages += message + "<br/>";
    182       }
    183       let formElement = document.getElementById(
    184         "custom-validation_" + Object.keys(model)[0]
    185       );
    186       let formitemWrapper =
    187         formElement.parentElement.parentElement.parentElement;
    188       let lanTippy2 = formitemWrapper.lanTippy;
    189       if (lanTippy2) {
    190         lanTippy2.setContent(errorMessages);
    191         lanTippy2.enable();
    192         lanTippy2.show();
    193       } else {
    194         let lanTippy = tippy(formitemWrapper, {
    195           content: errorMessages,
    196           allowHTML: true,
    197         });
    198         lanTippy.show();
    199         formitemWrapper.lanTippy = lanTippy;
    200       }
    201     },
    202     setFormFieldValidate: function (formRef, fields) {
    203       let self = this;
    204       let formModel = formRef.model;
    205       let formRules = formRef.rules;
    206       if (!formModel) {
    207         throw "表单未设置model";
    208       }
    209       if (!formRules) {
    210         throw "表单未设置rules";
    211       }
    212       if (formRef.$el.className.indexOf("lan-form") == -1) {
    213         formRef.$el.className = formRef.$el.className + " lan-form";
    214       }
    215 
    216       let model = {};
    217       if (fields && fields instanceof Array) {
    218         for (let i = 0; i < fields.length; i++) {
    219           let f = fields[i];
    220           model[f] = formModel[f];
    221         }
    222       } else if (fields && fields instanceof String) {
    223         model[fields] = formModel[fields];
    224       } else {
    225         model = formModel;
    226       }
    227       for (let key in model) {
    228         let ruleItemArr = formRules[key];
    229         if (!ruleItemArr) {
    230           continue;
    231         }
    232         let miniRuleArr = [];
    233         for (let i = 0; i < ruleItemArr.length; i++) {
    234           let orginalRuleInfo = ruleItemArr[i];
    235           let ruleInfo = JSON.parse(JSON.stringify(orginalRuleInfo));
    236 
    237           let miniValidateField = function (rule, value, callback) {
    238             // if(rule&&(rule.field=='validator'||rule.field=='asyncValidator')){debugger;
    239             //     return;
    240             // }
    241             let ruleObj = {};
    242             ruleObj[this.key] = this.rule;
    243             let modelObj = {};
    244             modelObj[this.key] = value;
    246             self.validateField(
    247               modelObj,
    248               ruleObj,
    249               false,
    250               self.validateSucessCallback,
    251               self.validateFailCallback,
    252               callback
    253             );
    254           };
    255           if (orginalRuleInfo.validator) {
    256             ruleInfo.validator = orginalRuleInfo.validator;
    257             orginalRuleInfo.validator = miniValidateField.bind({
    258               key: key,
    259               rule: ruleInfo,
    260             });
    261           } else if (orginalRuleInfo.asyncValidator) {
    262             ruleInfo.asyncValidator = orginalRuleInfo.asyncValidator;
    263             orginalRuleInfo.asyncValidator = miniValidateField.bind({
    264               key: key,
    265               rule: ruleInfo,
    266             });
    267           } else {
    268             orginalRuleInfo.validator = miniValidateField.bind({
    269               key: key,
    270               rule: ruleInfo,
    271             });
    272           }
    273         }
    274       }
    275     },
    276   },
    277 
    278   mounted: function () {
    279     this.setFormFieldValidate(this.$refs.formRef);
    280   },
    281 };
    282 </script>
    283 
    284 <style lang="less">
    285 .lan-form {
    286   .ant-form-item-control {
    287     border-radius: 5px;
    288     .ant-input,
    289     .ant-input-number {
    290       border-radius: 5px;
    291     }
    292   }
    293   .ant-form-item {
    294     margin-bottom: 5px;
    295   }
    296   .ant-form-explain {
    297     display: none;
    298   }
    299   .ant-input-number {
    300      100%;
    301     .ant-input-number-handler-wrap {
    302       display: none;
    303     }
    304   }
    305 }
    306 </style>

    最小环境校验

    官方文档Form有这么一个事件,validate,任一表单项被校验后触发

  • 相关阅读:
    Softmax
    网络流模板大全
    简单数据结构题(from 钟子谦——IOI2018集训队自选题)
    [POJ3177]Redundant Paths
    [BZOJ1051][HAOI2006]受欢迎的牛
    [BZOJ2036]聪明的阿卑多
    [BZOJ1455]罗马游戏
    [POJ2942][LA3523]Knights of the Round Table
    [POJ3352]Road Construction
    练级(train)
  • 原文地址:https://www.cnblogs.com/ZhyjEye/p/14669046.html
Copyright © 2020-2023  润新知