文章目录

  • Update 20210601
  • Update 20210525
  • 原文:
    • 1.a-form的model
    • 2.获取数据
  • 源码

Update 20210601

今天做别的页面的时候发现又取不到数据了
测试发现应该是name需要和数据项里面的对象同名
比如下面这个例子,我的数据是relate.related_name
那name就需要设置成related_name,如果设置成别的name就取不到数据

// 这个行!
<a-form-item label="姓名" name="related_name"><a-input v-model:value="relate.related_name"/></a-form-item>// 这个不行!
<a-form-item label="姓名" name="name"><a-input v-model:value="relate.related_name"/></a-form-item>

Update 20210525

事情太多,终于有时间继续写代码,用了以后发现我之前的formRef只能验证一个最后一个Form,原理其实和我那个错误一样,我用了同一个ref()所以每次v-for之后都会被最后一个Form的ref覆盖,导致每次只能验证最后一个Form,所以重新对代码进行更新。将formref也修改成一个数组,为了方便把数据Json化,没有选择把数据放在数据数组里面,而是弄了一个数据数组一起动态增加的REF数组,当然这种方法很容易出问题,后续代码优化过程中需要将增加数据的操作在抽象一下。完成代码请大家拉到最后的代码中去看,已经更新了。又要去干杂活了,代码没啥时间整理,直接整个贴,更新主要是怕误导大家,大家将就着看一下。

<a-formv-for="(filial, index) in filialValidateForm.filials":key='index':model="filialValidateForm.filials[index]":ref="filialValidateForm.formrefs[index]":rules="rules":label-col="labelCol":wrapper-col="wrapperCol">
interface FormData {filials: FilialInfo[],formrefs: Ref[],
}
const filialValidateForm: UnwrapRef<FormData> = reactive({filials: [],formrefs: [],})

原文:

大家好,我是橘子,今天继续来搞搞前端
这次是用了Ant Design of Vue这个库,下文简称AD。说实话这个库到底叫什么,为什么起这种带空格的名字我是没理解。
https://2x.antdv.com/components/form-cn#components-form-demo-dynamic-form-item

日常吐槽:我真的是不理解前端的生态,我觉得挺奇怪的,说AD算是使用范围比较广的框架了吧,但是百度上问题基本上找不到答案。。不知道是因为名字太长还是版本变动太快。还是百度垃圾。

好了,言归正传,说说这两天遇到的问题。
先描述下需求,我需要用户填一个子女信息的表单,表单里面有姓名、性别等好几个item需要用户填写。然后这个表单可以动态增加的。看了DEMO(DEMO链接:链接)里面的实现。
哦吼不难嘛,就是用v-for搭配控制表单的数组来动态完成就可以了。那就上手试试。

页面样式的部分问题不大,很快就能增加表单。问题出现在数据校验这块。

一开始我用了同一个form然后再里面用一个div进行v-for
我发现我定义的验证函数取到的value值一直是空的。

经过我的不泄努力最后发现新手们有几个地方需要注意:

1.a-form的model

这里绑定的数据不能是你的页面数组,所以,就不能和我一样把v-for放在子元素div里面循环,而要放在form里面循环,这样才能拿到具体的数据对象。
比如我根据DEMO把数据类型设定成这样

const filialValidateForm: UnwrapRef<{ filials: FilialInfo[] }> = reactive({filials: [],})

如果按照我之前的做法:v-for部分放在div里面,你会发现他没有办法正常工作,无论你填写什么他都显示你没填写。测试下来,你修改提示关键字什么的他都能识别,证明他是可以识别到rules的,说明问题不在这。测试自定义规则的时候会发现value一直是undefined。但是我们去取值,会发现数据是有好好绑定到数据对象上面的,我们通过代码是可以获取填写的值的。

<a-form:rules="rules":label-col="labelCol":wrapper-col="wrapperCol"><divv-for="(filial, index) in filialValidateForm.filials":key='index':model="filial"ref="formRef">

‘XXX’ is required

那猜测问题是出现在这个model上面,我猜测是由于这个遍历的数据对象(filial)无法在Form组件里面获取,而我们的数据验证是依托于这个form的ref这个引用对象来做的。所以你在子元素遍历这个数据数组的时候无法将它绑定到ref上面,导致整个表单的数据无法验证。
那解决办法是啥嘞?两个思路,第一个是在子元素的div里面获取ref,但是这个对我这个菜鸡来说太复杂了,索性就以第二个思路来做,把这个v-for塞到a-form里面。我本能的觉得这个行为很奇怪,但是又说不出来哪里怪,如果这么做有什么风险请各位大佬帮我指出。
改成这样之后我猜是因为在这层ref可以获取到我这里遍历的filial这个对象了,所以就可以绑定上了。

<a-formv-for="(filial, index) in filialValidateForm.filials":key='index':model="filial"ref="formRef":rules="rules":label-col="labelCol":wrapper-col="wrapperCol">

然后把按钮放到表单外,当然现在这个按钮都已经没有那个提交的事件了,所以放哪里也都一样。

2.获取数据

接下来是获取数据,获取数据之前肯定得先看一下我们输入验证的情况嘛,根据文档里面大概是这样的。

formRef.value.validate().then(() => {console.log('success');//验证成功打开确认提交遮罩层formState.modalShow = true}).catch((error: ValidateErrorEntity<FormState>) => {console.log('value error', error);});

这里又遇到一个问题,如果你在这里去输出看一下formRef.value的值你可能会三观尽毁,怎么会这样反复横跳?
一会你可以调用到validate函数,一会又调用不到,到底是怎么回事呢?

你可以和我一样打印一下formRef.value的值,找一下里面有没有一个FormContext的对象,这个对象我不知道什么时候会出现,我发现的情况是:

1.当你只有通过代码插入form的时候,无论插入几个,当通过代码填写的数据未被手工修改的情况下,可以直接使用formRef.value.validate()。
2.当你用代码添加form且form里面的数据被手动修改过的情况下,需要用formRef.value.FormContext.validate()。

通过文档你可以看出,可以调用到validate这方法的时候,我们这个应该就是formRef应该是指向一个Form对象

我有看了一下源码,源码里面的FormContext应该是Form给FormItem父子通讯的一个类。

也就是说,出现了FormContext应该是因为我的ref被污染了,我取到了子对象的Form.Item的ref,那原因的很明显了,是我在解决前面无法获取value问题的瞎碰的时候乱抄作业导致的,后面的FormItem污染了我的ref,所以在修改这几个Input后导致ref被替换了。把其他的formRef删除之后就不会出现反复横跳的问题了。

// 注意这里的formRef
<a-form-item ref="formRef" label="工作单位" name="filial_work_place"><a-input v-model:value="filial.filial_work_place"/>
</a-form-item>
<a-form-item ref="formRef" label="职位" name="filial_title"><a-input v-model:value="filial.filial_title"/>
</a-form-item>

最后附上我整个逻辑的vue文件上来,整体逻辑还没做完,但测试的功能点已经差不多了,大家就不要吐槽我的代码风格了,我都是个人开发自己看看嘛,懒。
我是llsxily,你可以叫我菜鸡。(:з」∠)

源码

<template><div v-if="formState.showPage"><a-row :span="20" type="flex" justify="center"><a-col :span="24"><a-modal:title="formState.modalTitle"v-model:visible="formState.modalShow":confirm-loading="formState.modalConfirmLoading"@ok="handleOk":maskClosable="false":cancel-button-props="{ disabled: formState.modalCancelBtnDisabled}":cancelText="formState.modalCancelText":okText="formState.modalOkText"><p>{{ formState.modalText }}</p></a-modal><a-formv-for="(filial, index) in filialValidateForm.filials":key='index':model="filialValidateForm.filials[index]":ref="filialValidateForm.formrefs[index]":rules="rules":label-col="labelCol":wrapper-col="wrapperCol"><div><a-card :title="filial.filial_name"><template #extra><a-popconfirm:title="`是否删除 ${ filial.filial_name } 的信息`"ok-text="确认"cancel-text="取消"@confirm="deleteItem(index)"><a href="#">删除该项</a></a-popconfirm></template><a-form-item label="个人姓名" name="filial_name"><a-input v-model:value="filial.filial_name"/></a-form-item><a-form-item label="性别" name="filial_sex"><a-radio-group v-model:value="filial.filial_sex"><a-radio value="男">男</a-radio><a-radio value="女">女</a-radio></a-radio-group></a-form-item><a-form-item label="身份证号" name="filial_id"><a-input v-model:value="filial.filial_id"/></a-form-item><a-form-item label="工作单位" name="filial_work_place"><a-input v-model:value="filial.filial_work_place"/></a-form-item><a-form-item label="职位" name="filial_title"><a-input v-model:value="filial.filial_title"/></a-form-item></a-card></div></a-form><a-form-item :wrapper-col="{ span: 14, offset: 4 }" style="margin-top: 10px"><a-button type="primary" @click="onAddEmptyFilial">增加子女</a-button><a-button style="margin-left: 10px" type="primary" @click="onSubmit">提交信息</a-button></a-form-item></a-col></a-row></div>
</template><script lang="ts">
import {inject, reactive, ref, UnwrapRef, Ref} from "vue";
import axios from "axios";
import Store from "@/store/store";
import {RuleObject, ValidateErrorEntity} from "ant-design-vue/es/form/interface";
import {notification} from "ant-design-vue";interface FilialInfo {filial_name: stringfilial_id: stringfilial_work_place: stringfilial_sex: stringfilial_title: string
}interface FormState {showPage: booleannameType: booleanmodalTitle: stringmodalShow: booleanmodalText: stringmodalCancelBtnDisabled: booleanmodalConfirmLoading: booleanmodalCancelText: stringmodalOkText: string
}interface FormData {filials: FilialInfo[],formrefs: Ref[],
}export default {name: "FilialContent",setup() {// 表单状态控制类const formState: UnwrapRef<FormState> = reactive({showPage: false,nameType: false,// modal状态控制modalTitle: '警告',modalText: '是否确认提交子女信息数据',modalShow: false,modalCancelBtnDisabled: false,modalConfirmLoading: false,modalCancelText: "取消",modalOkText: "确认",})// 整体数据对象const filialValidateForm: UnwrapRef<FormData> = reactive({filials: [],formrefs: [],})// 校验规则const rules = {filial_name: [{required: true, message: '请填写姓名', trigger: 'blur'}],filial_sex: [{required: true, message: '请填写性别', trigger: 'blur'}],filial_id: [{required: true, message: '请填写身份证号码', trigger: 'blur'}],filial_work_place: [{required: true, message: '请填写工作单位', trigger: 'blur'}],filial_title: [{required: true, message: '请填写职位', trigger: 'blur'}],};// 业务流// 从父组件获取tokenconst token = inject(Store.token)// 数据初始化let params = new URLSearchParams()params.append('zzybjj_token', String(token))params.append('type', '2')axios.post('/get_other_info/', params).then((response) => {console.log(response.data)if (response.data.filial_num == 0) {onAddEmptyFilial()} else {console.log(response.data.filial_data.length)let dataArr = response.data.filial_datafor (let key in dataArr) {addInfo(dataArr[key])}}formState.showPage = true})// 按钮回调函数// 增加空卡片let is_addFilial = falseconst onAddEmptyFilial = () => {is_addFilial = truelet m_filial: UnwrapRef<FilialInfo> = {filial_name: '',filial_id: '',filial_work_place: '',filial_sex: '',filial_title: '',}filialValidateForm.filials.push(m_filial)filialValidateForm.formrefs.push(ref())}// 添加数据卡片const addInfo = (data: any) => {let m_filial: UnwrapRef<FilialInfo> = {filial_name: data.name,filial_id: data.id,filial_work_place: data.work_place,filial_sex: data.sex,filial_title: data.title,}filialValidateForm.filials.push(m_filial)filialValidateForm.formrefs.push(ref())}// 删除项目const deleteItem = (key: string) => {console.log(key)// 从数组中删除对应数据filialValidateForm.filials = filialValidateForm.filials.filter(obj => obj !== filialValidateForm.filials[Number(key)])filialValidateForm.formrefs = filialValidateForm.formrefs.filter(obj => obj !== filialValidateForm.formrefs[Number(key)])}// 提示窗打开函数const openNotificationWithIcon = (type: string, title: string, description: string) => {notification[type]({message: title,description: description,});};// 取数工具函数const getFormData = () => {let params = new URLSearchParams();console.log(filialValidateForm)console.log(JSON.stringify(filialValidateForm.filials))params.append('filials_data', JSON.stringify(filialValidateForm.filials))params.append('zzybjj_token', String(token))return params}// Modal状态重置工具函数const resetModal = () => {formState.modalText = '是否确认提交子女信息数据'formState.modalShow = falseformState.modalCancelBtnDisabled = falseformState.modalConfirmLoading = false}// 提交按钮回调函数const onSubmit = () => {if (filialValidateForm.filials.length == 0) {// 无数据确认框formState.modalText = '当前无数据,如果继续提交会删除之前的数据,确认提交吗?'formState.modalShow = truereturn} else {console.log(filialValidateForm.filials)console.log(filialValidateForm.formrefs)for(let key in filialValidateForm.filials){console.log(key)filialValidateForm.formrefs[key].value.validate().then(()=>{onCheckdate(true)}).catch((error: ValidateErrorEntity<FormState>) => {console.log('value error', error);onCheckdate(false)})}}}let checkCount = 0let checkRet = trueconst onCheckdate = (ret: boolean) =>{checkCount += 1checkRet = checkRet && retif(checkCount == filialValidateForm.formrefs.length){formState.modalShow = checkRetcheckRet = truecheckCount = 0}}// 确认提交函数const handleOk = () => {formState.modalCancelBtnDisabled = trueformState.modalText = '返回结果前请勿关闭浏览器'formState.modalConfirmLoading = truelet params = getFormData()axios.post('/save_filial_info/', params).then((response) => {resetModal()if (response.data.code === 200) {openNotificationWithIcon('success', '成功', '子女信息已保存')}console.log(response.data)})}return {labelCol: {span: 5},wrapperCol: {span: 13},other: '',rules,formState,filialValidateForm,deleteItem,onAddEmptyFilial,onSubmit,handleOk,};}
}
</script><style scoped></style>

Ant Design of Vue +TS 表单动态增加数据验证卧坑姿势相关推荐

  1. UI组件库Form表单_数字类型验证之坑实现数字框

    目录 Input 输入框 实现数字框封装使用 项目需求 : 使用的饿了么组件库的 input 框 , 但是想要 实现用户只能输入 数字 的功能 , So 看到了数字类型的验证 (缺点 :不能阻止用户输 ...

  2. ant design pro vue 动态路由 流程详解

    ant design pro vue 动态路由 流程详解 前言 流程图 流程1 src/permission.js 流程2 src/store/modules/user.js 流程3 src/perm ...

  3. 创建Vue+TS+Ant Design of Vue 项目

    创建Vue+TS+Ant Design of Vue 项目 创建项目 选择配置 运行项目 安装 ant-design-vue 安装 babel-plugin-import 使用VS Code打开 配置 ...

  4. Vue.js高效前端开发 • 【Ant Design of Vue框架进阶】

    全部章节 >>>> 文章目录 一.栅格组件 1.栅格组件介绍 2.栅格组件使用 3.实践练习 二.输入组件 1.输入框组件使用 2.选择器组件使用 3.单选框组件使用 4.实践 ...

  5. activeform表单中的旧数据怎么显示_三分钟为你细数 Vue el-form 表单校验的坑点

    背景 Vue 的 el-form 提供了表单校验功能,通过 :rules 属性设置校验规则,并通过 el-form-item 的 prop 属性绑定校验规则.通过封装,让前端校验更方便.具体使用过程中 ...

  6. element实现form表单动态添加email效果

    前言: vue中使用element实现form表单动态添加email效果 效果: 实现步骤: 实现源代码: <template><div><el-form ref=&qu ...

  7. vue自定义表单设计器思路

    Vue是一种流行的JavaScript框架,用于构建Web应用程序.Vue的灵活性使得它成为一种非常适合创建自定义表单设计器的框架.本文将介绍如何使用Vue实现一个自定义表单设计器,并最终实现单据自定 ...

  8. 使用Ant Design 和Vue,React中后台开发套餐

    2019独角兽企业重金招聘Python工程师标准>>> 前言 目前Ant Design 提供 React 和 Vue 两种整合开发框架,开箱即用的中台前端/设计解决方案,可适合中小公 ...

  9. [vue] 说说你对vue的表单修饰符.lazy的理解

    [vue] 说说你对vue的表单修饰符.lazy的理解 input标签v-model用lazy修饰之后,vue并不会立即监听input Value的改变,会在input失去焦点之后,才会触发input ...

最新文章

  1. grails 环境找不到java_home
  2. 用Python Pandas处理亿级数据
  3. 智慧城市:解构成渝城市群一体化
  4. 浏览器 user-agent 字符串的故事
  5. c语言定义数组变量初始化为0,c语言数组初始化——int a[N] = {0};
  6. qq显示下线通知什么意思_最近时不时地收到QQ下线的通知
  7. 从 0 经验到成为全球第一模组生产商,日海智能的「非典型」物联网之路
  8. 我的年终总结:做了9年SOC的一点点实践体会
  9. Python源码剖析(四)字符串对象
  10. 计算机固态硬盘安装,台式计算机的固态硬盘安装方法和步骤教程
  11. Python程序员培训计划
  12. 线性代数————思维导图(上岸必备)(线性方程组)
  13. html里面链接,html – 链接里面的一个链接
  14. java唯一订单号_java高并发下唯一订单号生成器【16位数字订单号】
  15. linux实现文件共享的方式,Linux文件共享的实现方式
  16. 计算机桌面下方叫什么,电脑最下面一排桌面的小图标不见了
  17. 博士申请 | 港中深韩晓光课题组招收与华为中央媒体院联合培养博士生
  18. App_Offline.htm 问题解决
  19. Unity 网络请求
  20. 图片如何转换为文字?这些软件可以实现

热门文章

  1. 根据word模板(书签)创建导出word
  2. 【经验篇】聊聊双非计算机硕士如何进大厂搞算法
  3. 【oracle11g,11】redo日志文件2 :日志恢复 (重点)
  4. 【Unity】如何删除不要的Tile Palette(瓦片地图)(遇到新的问题就继续更新2021.4.29)
  5. 修改Linux中发送邮件中附件大小的限制
  6. 25.(cesium篇)cesium军事标绘-攻击箭头采集(燕尾)
  7. 92_特殊方法(魔术方法)和运算符重载
  8. BZOJ 1123: [POI2008]BLO
  9. 漏洞风险评估:CVSS介绍及计算
  10. 分享一款多线程磁力搜索工具-聚磁帮