ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-04-16 23:05:42  阅读:1350  来源: 互联网

标签:function vue fields rule 表单 let key antd model


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

最近学习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     width: 100%;
301     .ant-input-number-handler-wrap {
302       display: none;
303     }
304   }
305 }
306 </style>

 

 

 

 

 

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

 

标签:function,vue,fields,rule,表单,let,key,antd,model
来源: https://www.cnblogs.com/ZhyjEye/p/14669046.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有