ViewUI表格Table嵌套From表单-动态校验数据合法性的解决方法

文章讲述了如何在使用原生HTML构建的表格中实现动态数据添加和输入框的实时校验,避免显示冗余的错误提示,并在Vue组件中使用`v-for`循环展示数据并进行格式化和权限控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

项目需求:在表格中实现动态加减数据,并且每行表格内的输入框,都要动态校验数据,校验不通过,不让提交数据,并且由于表格内部空间较小,我仅保留红边框提示,文字提示给隐藏了,不然表格内的框会很大很难看。

如果,你需要提示的话,不要show-message属性

            <Form ref="formDynamic"
                  :model="obj"
                  :label-width="15"
                  :show-message="false" //去掉这一行代码就显示校验错误信息了
                  inline
            >

问题描述

提示:在表格中实现动态加减数据,并且每行表格内的输入框,都要动态校验数据

在这里插入图片描述

在这里插入图片描述

原因分析:

提示:这里我并没有用viewUI的table组件,用的是原生html做的表格,然后样式做成和table组件相似,我不用table组件,是因为组件限制太多,组件用v-for渲染表格达不到项目需求,并且内部prop也检测不到校验。

这边的代码是精简的,里面核心的代码就在这,如果不是很明白的话,下面有全部代码

           <Form ref="formDynamic"
                  :model="obj"
                  :label-width="15"
                  :show-message="false"
                  inline
            >
              	<table id="formDynamic" style="border:  1px solid #e8eaec;border-collapse: collapse;">
                	<th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保险费用</th>
                	<tr v-for="(item, index) in obj.modelData"
	                    :key="index"
	                    style="border:  1px solid #e8eaec"
                	>
                    <td style="border:  1px solid #e8eaec;padding: 7px">
	                    <FormItem
	                        label=" "
	                        :prop="'modelData.'+index+'.insuranceFee'"
	                        :rules="[{required: true, type:'number', message: '请输入', trigger: 'blur'},
	                        {pattern:/^(0|([1-9]\d*))(\.\d{1,2})?$/, message: '请输入正数'}]"
	                    >
	                      <Input
	                          v-model.trim.number="obj.modelData[index].insuranceFee"
	                          :show-word-limit='true'
	                          :maxlength="10"
	                          :disabled="Boolean(flag)"
	                      ></Input>
                    	</FormItem>
	                  </td>
                  </tr>
                </table>
             </Form>

解决方案:

提示:全部代码:

  <template>
            <Form ref="formDynamic"
                  :model="obj"
                  :label-width="15"
                  :show-message="false"
                  inline
            >
              <table id="formDynamic" style="border:  1px solid #e8eaec;border-collapse: collapse;">
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保险编号</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保险费用</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保险类型</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保险应收</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保险实收</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">保单欠款</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">收费开始时间</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">收费截止时间</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">备注</th>
                <th style="border:  1px solid #e8eaec;padding: 8px 0;background-color: #f8f8f9">操作</th>
                <tr v-for="(item, index) in obj.modelData"
                    :key="index"
                    style="border:  1px solid #e8eaec"
                >
                  <!--                  保险编号-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.insuranceId'"
                        style="width: 120px"
                        :rules="{required: true, message: '请输入', trigger: 'change'}">
                      <Select
                          v-if="!Boolean(flag)"
                          transfer
                          v-model="obj.modelData[index].insuranceId"
                          @on-change="changeBd(item,index)"
                      >
                        <Option
                            v-for="item in policyData"
                            :value="item.id"
                            :key="item.id"
                        >{{ item.insuranceCode }}
                        </Option
                        >
                      </Select>
                      <Input v-else :disabled='Boolean(flag)' v-model="obj.modelData[index].insuranceCode"></Input>
                    </FormItem>
                  </td>
                  <!--                  保险费用-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.insuranceFee'"
                        :rules="[{required: true, type:'number', message: '请输入', trigger: 'blur'},
                        {pattern:/^(0|([1-9]\d*))(\.\d{1,2})?$/, message: '请输入正数'}]"
                    >
                      <Input
                          v-model.trim.number="obj.modelData[index].insuranceFee"
                          :show-word-limit='true'
                          :maxlength="10"
                          :disabled="Boolean(flag)"
                      ></Input>
                    </FormItem>
                  </td>
                  <!--                  保险类型-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.insuranceType'"
                        :rules="{required: true, message: '请输入'}">
                      <Input type="text" disabled v-model="item.insuranceType" placeholder="请输入..."></Input>
                    </FormItem>
                  </td>
                  <!--                  保险应收-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.insuranceReceivables'"
                        :rules="[{required: true, type:'number',  message: '请输入', trigger: 'blur'},
                        {pattern:/^(0|([1-9]\d*))(\.\d{1,2})?$/, message: '请输入正数'}]"
                    >
                      <Input
                          v-model.trim.number="obj.modelData[index].insuranceReceivables"
                          @on-change="calculateCost(item,index)"
                          :show-word-limit='true'
                          :maxlength="10"
                          :disabled="Boolean(flag)"
                          @input="e => handleInput(e,'insuranceReceivables')"
                      ></Input>
                    </FormItem>
                  </td>
                  <!--                  保险实收-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.insurancePaid'"
                        :rules="[{required: true, type:'number',  message: '请输入', trigger: 'blur'},
                        {pattern:/^(0|([1-9]\d*))(\.\d{1,2})?$/, message: '请输入正数'}]"
                    >
                      <Input
                          v-model.trim.number="obj.modelData[index].insurancePaid"
                          @on-change="calculateCost(item,index)"
                          :show-word-limit='true'
                          :maxlength="10"
                      ></Input>
                    </FormItem>
                  </td>
                  <!--                  保险欠款-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.insuranceDebt'"
                        :rules="[{required: true, validator: '',  message: '请输入',type:'number', trigger: 'blur'},
                        {pattern:/^(0|([1-9]\d*))(\.\d{1,2})?$/, message: '请输入正数'}]"
                    >
                      <Input
                          v-model.trim.number="obj.modelData[index].insuranceDebt"
                          disabled=""
                      ></Input>
                    </FormItem>
                  </td>
                  <!--                  收费开始时间-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.startTime'"
                        :rules="{required: true, message: '请输入'}">
                      <DatePicker type="date"
                                  transfer
                                  format="yyyy-MM-dd"
                                  @on-change="obj.modelData[index].startTime = $event, setOptions($event,item,index,'start')"
                                  placeholder="开始时间"
                                  v-model="obj.modelData[index].startTime"
                                  :disabled="Boolean(flag)"
                      >
                        <!--                    @on-change="modelData[index].startTime = $event"-->
                      </DatePicker>
                    </FormItem>
                  </td>
                  <!--                  收费截止时间-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=" "
                        :prop="'modelData.'+index+'.endTime'"
                        :rules="{required: true, message: '请输入'}">
                      <DatePicker type="date"
                                  transfer
                                  format="yyyy-MM-dd"
                                  :options='timeOptions[timeIndex]'
                                  placeholder="截止时间"
                                  @on-change="obj.modelData[index].endTime = $event"
                                  @on-open-change="setOptions($event,item,index, 'end')"
                                  v-model="obj.modelData[index].endTime"
                                  :disabled="Boolean(flag)"
                      >
                      </DatePicker>
                    </FormItem>
                  </td>
                  <!--                  备注-->
                  <td style="border:  1px solid #e8eaec;padding: 7px">
                    <FormItem
                        label=""
                        :label-width="0"
                        :prop="'modelData.'+index+'.remark'"
                    >
                      <Input
                          v-model="obj.modelData[index].remark"
                          :show-word-limit='true'
                          :maxlength="100"
                          :disabled="Boolean(flag)"
                      ></Input>
                    </FormItem>
                  </td>
                  <!--                  操作-->
                  <td style="border:  1px solid #e8eaec;padding: 0px 7px 0px 7px;width: 180px;text-align: center">
                    <Button type="primary" style="" @click="cuteFTP(row,index)"
                            v-permission="'alliance:business:record:insurance:upload'"
                    >上传
                    </Button>
                    <Poptip
                        v-if="!flag"
                        confirm
                        :transfer="true"
                        title="你确定删除吗?"
                        @on-ok="delInsurance(index)"
                    >
                      <Button type="error">
                        <Icon type="md-trash"/>
                        删除
                      </Button>
                    </Poptip>
                  </td>
                </tr>
              </table>
            </Form>
          </template>
### 实现嵌套表单的必填校验并自动滚动到未填写文本框 在 `Element UI` 中,当需要在一个嵌套结构(如 `el-table` 和 `el-form` 组合)中实现必填校验,并且希望自动滚动到未填写的文本框时,可以按照以下方式进行设计。 #### 1. **解决输入框失去焦点问题** 如果遇到 `el-input` 输入一个字后失去焦点的情况,通常是因为动态渲染引起的。可以通过调整 `key` 属性来解决问题。例如,在表格中的每一行设置唯一的索引作为 `key` 值[^1]: ```html <el-table :data="tableData"> <el-table-column prop="name" label="名称"> <template slot-scope="scope"> <el-form-item :prop="'rows.' + scope.$index + '.name'" :rules="rules.nameRules"> <el-input v-model="scope.row.name" :key="scope.$index"></el-input> </el-form-item> </template> </el-table-column> </el-table> ``` 通过上述方式,确保每次渲染都基于固定的索引来绑定数据,从而避免因频繁重绘而导致的失焦现象。 --- #### 2. **嵌套表单校验逻辑** 对于嵌套表单校验,可以在父级 `el-form` 上定义统一的校验规则,并针对子组件内的字段进行路径映射。以下是完整的代码示例: ```html <el-form ref="formRef" :model="formData" :rules="rules"> <el-table :data="formData.rows"> <el-table-column prop="name" label="名称"> <template slot-scope="scope"> <el-form-item :prop="'rows.' + scope.$index + '.name'" :rules="rules.nameRules"> <el-input v-model="scope.row.name"></el-input> </el-form-item> </template> </el-table-column> </el-table> <!-- 提交按钮 --> <el-button type="primary" @click="submitForm">提交</el-button> </el-form> ``` 其中,`formData` 是整个表单数据模型,而 `rules` 定义了具体的校验规则: ```javascript export default { data() { return { formData: { rows: [ { name: '' }, { name: '' } ] }, rules: { nameRules: [{ required: true, message: '请输入名称', trigger: 'blur' }] } }; }, methods: { submitForm() { this.$refs.formRef.validate(valid => { if (valid) { console.log('提交成功'); } else { // 失败后的处理逻辑 this.scrollToFirstError(); return false; } }); }, scrollToFirstError() { setTimeout(() => { const isError = document.querySelectorAll('.el-form-item.is-error'); if (isError.length > 0) { isError[0].scrollIntoView({ behavior: 'smooth' }); } }, 100); } } }; ``` 在此代码中,`scrollToFirstError` 方法会在校验失败后延迟执行,以等待 Vue 更新 DOM 结构后再定位错误位置[^3]。 --- #### 3. **优化 ESLint 配置以支持代码风格一致性** 为了保持目代码的一致性和可维护性,建议配置 ESLint 来规范化代码格式。具体操作如下: - 创建 `.eslintrc.js` 文件: ```javascript module.exports = { root: true, env: { node: true }, extends: ['plugin:vue/essential', '@vue/prettier'], parserOptions: { ecmaVersion: 2020 }, rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', quotes: ['error', 'single'], // 使用单引号 semi: ['error', 'always'] // 强制分号结尾 } }; ``` 此配置禁用了不必要的语法规则,并强制使用单引号和分号结束语句[^2]。 --- #### 总结 以上方案解决了以下几个核心问题: 1. 动态渲染导致的输入框失焦问题; 2. 嵌套表单校验逻辑及其自动化处理; 3. 通过 JavaScript 调整页面视图至首个错误字段的位置; 4. 设置合理的 ESLint 规范以提升团队协作效率。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骆骆爱学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值