1、项目实际需求
如上图所示是要实现的业务场景,实现方式是利用el-form自带的校验规则。
2、代码实现
<template> <div id="app"> <div class="container"> <div class="header"> <div> <h2>表格动态校验示例</h2> <p class="tips">说明:开启“启用校验”开关后,对应的“项目名称”变为必填项。</p> </div> <div> <el-button type="primary" @click="submitForm" icon="el-icon-check">提交验证</el-button> <el-button @click="resetForm" icon="el-icon-refresh-left">重置</el-button> <el-button type="success" @click="addRow" icon="el-icon-plus">添加一行</el-button> </div> </div> <!-- 核心结构: 1. el-form 包裹整个表格,绑定 model 和 rules(虽然主要规则在 item 上动态绑定,但 form 是必须的上下文) 2. el-table 绑定 data --> <el-form ref="tableForm" :model="formModel"> <el-table :data="formModel.tableData" border style="width: 100%"> <!-- 索引列 --> <el-table-column type="index" label="序号" width="60" align="center"></el-table-column> <!-- 开关控制列 --> <el-table-column label="启用校验 (Switch)" width="180" align="center"> <template slot-scope="scope"> <el-switch v-model="scope.row.switchValue" active-text="开启" inactive-text="关闭" active-color="#13ce66" inactive-color="#ff4949"> </el-switch> </template> </el-table-column> <!-- 动态校验字段列 --> <el-table-column label="项目名称 (动态必填)" min-width="200"> <template slot-scope="scope"> <!-- 关键点 1: :prop 必须动态绑定,格式为 'dataPath.index.fieldName' 关键点 2: :rules 根据 scope.row.switchValue 动态返回规则数组 如果 switchValue 为 true,则应用必填规则;否则为空数组 [] --> <el-form-item :prop="'tableData.' + scope.$index + '.projectName'" :rules="scope.row.switchValue ? rules.projectNameRequired : []" > <el-input v-model="scope.row.projectName" placeholder="请输入项目名称" :disabled="!scope.row.switchValue" ></el-input> </el-form-item> </template> </el-table-column> <!-- 普通字段列(作为对比,始终非必填或固定规则) --> <el-table-column label="备注" min-width="200"> <template slot-scope="scope"> <el-input v-model="scope.row.remark" placeholder="选填备注"></el-input> </template> </el-table-column> <!-- 操作列 --> <el-table-column label="操作" width="100" align="center"> <template slot-scope="scope"> <el-button type="text" size="small" style="color: #f56c6c;" @click="deleteRow(scope.$index)"> 删除 </el-button> </template> </el-table-column> </el-table> </el-form> <div style="margin-top: 20px; text-align: right;"> <el-alert title="验证逻辑提示" type="info" description="点击提交按钮时,只有 Switch 开启的行才会校验 projectName 是否为空。Switch 关闭的行即使为空也能通过验证。" show-icon :closable="false"> </el-alert> </div> </div> </div> </template> <script> export default { name: 'table-data', data() { return { // 表单数据模型 formModel: { tableData: [ { id: 1, switchValue: true, projectName: '', remark: '默认开启校验' }, { id: 2, switchValue: false, projectName: '', remark: '默认关闭校验' }, { id: 3, switchValue: true, projectName: '已有项目C', remark: '已有数据' } ] }, // 定义规则集合 rules: { // 动态引用的必填规则 projectNameRequired: [ { required: true, message: '开启校验时,此项为必填', trigger: 'blur' }, { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' } ] } }; }, created(){ // 初始化数据 // todo }, mounted(){ }, methods: { // 提交验证 submitForm() { this.$refs.tableForm.validate((valid) => { if (valid) { this.$message({ message: '验证通过!数据已准备提交。', type: 'success' }); console.log('提交的数据:', this.formModel.tableData); } else { this.$message.error('验证失败,请检查标红字段。'); console.log('验证失败'); return false; } }); }, // 重置表单 resetForm() { this.$refs.tableForm.resetFields(); // 注意:resetFields 会将数据重置为初始值。 // 如果需要完全清空并恢复默认结构,可能需要重新赋值 tableData this.$message.info('表单已重置'); }, // 添加新行 addRow() { this.formModel.tableData.push({ id: Date.now(), // 简单生成唯一ID switchValue: true, // 新行默认开启校验,方便演示 projectName: '', remark: '' }); }, // 删除行 deleteRow(index) { this.$confirm('确定删除该行吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.formModel.tableData.splice(index, 1); this.$message({ type: 'success', message: '删除成功!' }); }).catch(() => {}); } } } </script> <style lang="less" scoped> #app { font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; background-color: #f5f7fa; padding: 20px; } .container { max-width: 1000px; margin: 0 auto; background: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); } .header { margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center; } .header h2 { margin: 0; color: #303133; } .tips { font-size: 12px; color: #909399; margin-top: 5px; } /* 自定义开关样式微调 */ .el-switch__label { font-size: 12px; } </style>3、代码说明
3.1、动态规则绑定核心逻辑:
- 在 <el-form-item> 上使用 :rules 属性进行动态绑定。
- 表达式 scope.row.switchValue ? rules.projectNameRequired : [] 实现了核心需求:当开关值为 true 时,应用包含 required: true 的规则数组;当开关值为 false 时,应用空数组 [],从而跳过必填校验。
3.2、正确的 Prop 路径映射:
- el-form-item 的 :prop 属性严格遵循 Element UI 表格校验规范,格式为 'tableData.' + scope.$index + '.projectName'。这确保了 el-form 的 validate 方法能够准确定位到表格中具体行的具体字段进行校验。
3.3、完整的交互体验:
- 开关联动:切换 Switch 状态会立即改变输入框的校验状态。如果从“开启”切换到“关闭”,之前的错误提示会在下次校验或重置时消失(因为规则变为空)。
- 禁用状态优化:为了用户体验,当 Switch 关闭时,输入框设置了 :disabled="!scope.row.switchValue",视觉上明确告知用户该字段当前不可编辑且无需填写。
- 增删改查支持:提供了添加行、删除行、重置表单和提交验证的功能,模拟了真实的业务场景。
4、总结
实现“开关开启则必填,关闭则非必填”的最佳实践是:
在 <el-form-item> 上使用 :rules 动态绑定。
- 当 scope.row.switchValue === true 时,绑定包含 { required: true } 的规则数组。
- 当 scope.row.switchValue === false 时,绑定空数组 [] 或不绑定 rules。
这种方式逻辑清晰,性能良好,且完全符合开发规范。