antd+vue3对循环的表单控件添加自定义校验
对循环的表单控件添加自定义校验
效果如下:
代码如下:
1 <template> 2 <a-form ref="formRef" :model="modelRef" v-bind="outLayout" class="layout"> 3 <a-form-item 4 v-for="(domain, index) in modelRef.domains" 5 :key="domain.key" 6 v-bind="itemLayout" 7 :label="'步骤' + (index + 1)" 8 :name="['domains', index, 'value']" 9 :rules="[ 10 { 11 required: true, 12 message: '步骤内容不能为空', 13 }, 14 { 15 max: 200, 16 message: '最多输入200字,请重新输入', 17 }, 18 ]" 19 > 20 <a-textarea 21 v-model:value.trim="domain.value" 22 placeholder="请输入(200字以内)" 23 style="width: 50%; margin-right: 8px" 24 /> 25 <MinusCircleOutlined 26 v-if="modelRef.domains.length > 1" 27 class="dynamic-delete-button" 28 :disabled="modelRef.domains.length === 1" 29 @click="removeDomain(domain)" 30 /> 31 </a-form-item> 33 <a-form-item v-bind="outLayout"> 34 <a-button type="dashed" style="width: 55%" @click="addDomain"> 35 <PlusOutlined /> 36 新增步骤 37 </a-button> 38 </a-form-item> 39 40 <a-button class="hidden" @click="onSubmit" /> 41 </a-form> 42 </template> 43 <script> 44 import { reactive, toRefs, watch } from 'vue' 45 import { cloneDeep } from 'lodash' 46 import { shareState } from './model' 47 48 export default { 49 setup() { 50 const state = reactive({ 51 formRef: null, 53 itemLayout: { 54 labelCol: { span: 2 }, 55 wrapperCol: { span: 15 }, 56 }, 57 outLayout: { 58 wrapperCol: { 59 span: 14, 60 offset: 2, 61 }, 62 }, 63 }) 64 const modelRef = reactive({ 65 domains: [], 66 }) 67
// 初始化 控件值 68 const initData = async () => { 69 const data = cloneDeep(shareState.formData.recipeStepList) 70 modelRef.domains = data.map(v => { 71 return { value: v, key: Date.now() + Math.random() } 72 }) 73 } 74 75 watch( 76 () => shareState.formData, 77 val => { 78 if (val) initData() 79 }, 80 { deep: true, immediate: true }, 81 ) 82
// 删除输入框 83 const removeDomain = item => { 84 const index = modelRef.domains.indexOf(item) 85 if (index !== -1) { 86 modelRef.domains.splice(index, 1) 87 } 88 } 89
// 添加输入框 90 const addDomain = () => { 92 modelRef.domains.push({ 93 value: null, 94 key: Date.now() + Math.random(), 95 }) 96 } 97
// 由于此模块作为组件被引入到其他页面(父组件),父组件有一个统一的保存按钮,点击此按钮时触发该onSubmit事件,以此校验该表单是否填写正确 98 const onSubmit = () => { 99 return state.formRef 100 .validate() 101 .then(() => { 107 const arr = modelRef.domains.map(v => v.value) 108 const data = arr.join('#') 109 return Promise.resolve(data) 110 }) 111 .catch(error => { 112 return Promise.reject(new Error(error)) 113 }) 114 } 115 116 return { 117 ...toRefs(state), 118 modelRef, 119 onSubmit, 120 removeDomain, 121 addDomain, 122 } 123 }, 124 } 125 </script> 126 <style lang="less" scoped> 127 .layout { 128 .dynamic-delete-button { 129 cursor: pointer; 130 position: relative; 131 top: 4px; 132 font-size: 24px; 133 color: #999; 134 transition: all 0.3s; 135 } 136 .dynamic-delete-button:hover { 137 color: #777; 138 }145 :deep(.ant-col-offset-2) { 146 margin-left: 6.5%; 147 } 148 :deep(.ant-col-2) { 149 max-width: 6.5%; 150 } 151 } 152 </style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!