使用element-ui中的el-form和el-table嵌套实现表格内容编辑并提交表格表单数据校验(可以对勾选到的表格内容必填校验+勾选框)

文章描述了如何在Vue应用中使用Element-UI实现一个包含表格的表单,其中表格中的表单项需要根据勾选行进行必填校验。作者分享了HTML结构、数据模型和如何处理复选框选择以及部分字段校验的代码示例。
摘要由CSDN通过智能技术生成

业务场景:有个页面需要用到表格的样式效果来进行采集用户输入内容进行表单提交,并且提交的时候需要对表格中的表单项做必填校验=> 注意这里有个关键点(校验的时候需要只根据勾选的表格行数据进行校验)。这里的难点在于怎么对表格中勾选到的行做必填校验。后来看到有网友跟我碰到了一样的问题就在这里跟大家分享下希望对有需要的人有帮助。
代码是使用 Vue + element-ui 实现的

这里我写了个demo大家先看下效果
在这里插入图片描述
这里点击保存的时候不仅校验表格中的输入框,还有上方的两个表单项。首先大家要明白这里的html结构是一个大表单 el-form里边嵌套的el-table,而el-table中又嵌套了表单项 el-form-item支持编辑。

看结构:

<el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
      <el-row>
        <el-col :span="6">
          <el-form-item label="姓名" prop="name">
            <el-input v-model="formData.name"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="6">
          <el-form-item label="年龄" prop="age">
            <el-input v-model="formData.age"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-table
        border
        ref="tableBox"
        :data="formData.tableData"
        @selection-change="handleSelectionChange"
        :row-style="{ height:'70px' }"
        :cell-style="{ padding:'0px' }">
        <el-table-column type="selection" min-width="60" align="center">
        </el-table-column>
        <el-table-column prop="province" label="省份" min-width="60" align="center">
        </el-table-column>
        <el-table-column prop="city" label="城市" :render-header="addRedStar" min-width="70" align="center">
          <template slot-scope="scope">
            <el-form-item :prop="'tableData.' + scope.$index + '.city'" :rules="rules.city">
              <el-input
                v-model="scope.row.city"
                maxlength="200"
                oninput="if(value.length > 200) value=value.slice(0, 200)"
                placeholder="请输入">
              </el-input>
            </el-form-item>
          </template>
        </el-table-column>
        <el-table-column prop="scenicArea" label="景区" :render-header="addRedStar" min-width="70" align="center">
          <template slot-scope="scope">
            <el-form-item :prop="'tableData.' + scope.$index + '.scenicArea'" :rules="rules.scenicArea">
              <el-input
                v-model="scope.row.scenicArea"
                maxlength="200"
                oninput="if(value.length > 200) value=value.slice(0, 200)"
                placeholder="请输入">
              </el-input>
            </el-form-item>
          </template>
        </el-table-column>
      </el-table>
    </el-form>
    <el-row style="margin-top: 50px">
      <el-col :span="24">
        <el-button type="primary" @click="submit">保存</el-button>
      </el-col>
    </el-row>

这里要注意数据结构,因为表格是嵌套在el-form表单中的,所以 表格el-table的数据应该是 :data=“formData.tableData” 表单对象下的表格数组,别忘了还要给表单定义rules校验规则,表格中表单校验需要绑定prop字段而这个字段是根据表格索引动态绑定的:

<el-form-item :prop="'tableData.' + scope.$index + '.city'" :rules="rules.city">

上边代码指的是通过表格索引将要校验的字段在表格数据中做对应。
我这里只写了输入框类型的表单做演示,大家可以根据自己需要灵活的使用其他表单项和添加自定义校验规则。

定义数据部分:

formData: {
        name: '',
        age: '',
        tableData: [
          { index: 0, province: '河南', city: '', scenicArea: '' },
          { index: 1, province: '北京', city: '', scenicArea: '' },
          { index: 2, province: '广州', city: '', scenicArea: '' }
        ]
      },
      rules: {
      name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
        age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
        city: [{ required: true, message: '请输入城市', trigger: 'blur' }],
        scenicArea: [{ required: true, message: '请输入景区', trigger: 'blur' }]
      },
      multipleSelection: [], //复选框勾选的表格数据
      verify: [] // 表格中勾选的要校验的字段

到这里表格中编辑的样式结构及定义的数据结构已经准备完毕,下边需要考虑怎么进行表单提交校验了。
通常我们使用表单校验都是用的el-form中的 validate()方法进行表单校验,因为这里我们给整个表格中的编辑字段都绑定了必填校验字段但是有复选框的存在我们需要对勾选行的部分字段做必填校验,这样的话validate()校验全部就不能用了。
后来翻饿了么文档发现了个我们很少用的方法 validateField()
在这里插入图片描述
通过这个方法我们可以实现对部分表单字段进行校验,需要往这个方法中传入我们需要校验的字段即可。但这里又会遇到一个问题我们如果只是校验表单对象形式的数据的话,校验字段rules还是一个一个的我们能够拿到,但el-table数组中每个格子绑定的校验字段怎么获取呢?上边给表格中的表单项绑定校验字段是根据表格索引动态指定的,还有勾选限制?大家此时脑海里要有这个表单表格的校验数据结构。
后来发现可以通过表单引用对象中的fields属性获取到所有要校验的字段。
然后根据勾选的表格数据做遍历筛选出表格勾选数据中需要校验的字段,没勾选到不需要校验的字段则去除校验。
我们在复选框勾选事件中进行遍历筛选出保存时需要校验的字段

声明的verify 就是表格中勾选的需要校验的字段,

// 复选框勾选事件
    handleSelectionChange (val) {
      this.multipleSelection = val
      // 获取表单所有要校验的字段
      const prop = this.$refs.formRef.fields.map(item => item.prop)
      if (val.length <= 0) return this.$refs.formRef.clearValidate(prop)
      this.verify = []
      // 将选中的数据和全部表格中校验的字段遍历 取出勾选对应的校验字段、并将没勾选的校验去除
      this.$refs.formRef.fields.forEach(item => {
        val.forEach(element => {
          if (item.prop.split('.')[1] === element.index.toString()) {
            this.verify.push(item.prop)
          } else {
            this.$refs.formRef.clearValidate(item.prop)
          }
        })
      })
      console.log(this.verify)
      // scope.$index当前行数据在数组中的索引,勾选哪一行校验哪一行的必填项
    },

然后 我们在保存的事件中 将表格中勾选的需要校验的字段verify 和 表格外
多余的其他表单项的必填校验字段 进行合并则是最终我们保存时需要校验的所有表单字段。
我这里还多做了个校验,如果没有勾选表格数据的话,需要勾选表格才能提交,这个是用Promise 加的,这个根据大家情况,可要可不要。
使用validateField() 表单校验的时候还需要注意啊这个方法有些特殊跟validate不一样,不是回调一下就能拿到校验结果的,而是你传入了多少个需要校验的字段他就会产生多少次回调,所以对于必填校验来说我们需要等她所有回调结束然后遍历所有的回调结果保证每次都校验通过才算是真正校验结束。

submit () {
      const f1 = new Promise((resolve, reject) => {
        if (this.multipleSelection.length > 0) {
          resolve('save!')
        } else {
          reject(this.$message.error('请勾选数据'))
        }
      })
      const ary = ['name', 'age']
      // 合并表格中勾选的和上方表单中要校验的字段
      const params = [].concat(this.verify, ary)
      Promise.all([f1]).then(() => {
        const validateFieldList = []
        this.$refs.formRef.validateField(params, isOk => {
          // 部分表单校验时,有几个校验字段就回调几次,isOk空的时候为通过,
          if (!isOk) {
            // 收集每次回调校验的结果等全部回调结束后再判断最终是否全部校验通过
            validateFieldList.push(isOk)
            const flag = validateFieldList.every((item) => item === '')
            // 判断校验的字段数量是否全部校验完且每个结果都是通过则证明最终校验通过
            if (validateFieldList.length === params.length && flag) {
              this.$message.success('保存成功')
            } else {
              return
            }
          }
        })
      })
    },

从开始写到实现效果遇到的问题还是比较多的,大家多注意我说的几个关键点捋清思路,然后我把完整demo代码放到下面可以直接粘贴看效果,这里只写了保存校验这个场景的也是最重要部分,另外编辑返显重置的情况代码有点多就不发了,大家明白了这个思路很多交互场景就都能实现了。

<template>
  <div class=''>
    <el-form ref="formRef" :model="formData" :rules="rules" label-width="100px">
      <el-row>
        <el-col :span="6">
          <el-form-item label="姓名" prop="name">
            <el-input v-model="formData.name"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="6">
          <el-form-item label="年龄" prop="age">
            <el-input v-model="formData.age"></el-input>
          </el-form-item>
        </el-col>
      </el-row>
      <el-table
        border
        ref="tableBox"
        :data="formData.tableData"
        @selection-change="handleSelectionChange"
        :row-style="{ height:'70px' }"
        :cell-style="{ padding:'0px' }">
        <el-table-column type="selection" min-width="60" align="center">
        </el-table-column>
        <el-table-column prop="province" label="省份" min-width="60" align="center">
        </el-table-column>
        <el-table-column prop="city" label="城市" :render-header="addRedStar" min-width="70" align="center">
          <template slot-scope="scope">
            <el-form-item :prop="'tableData.' + scope.$index + '.city'" :rules="rules.city">
              <el-input
                v-model="scope.row.city"
                maxlength="200"
                oninput="if(value.length > 200) value=value.slice(0, 200)"
                placeholder="请输入">
              </el-input>
            </el-form-item>
          </template>
        </el-table-column>
        <el-table-column prop="scenicArea" label="景区" :render-header="addRedStar" min-width="70" align="center">
          <template slot-scope="scope">
            <el-form-item :prop="'tableData.' + scope.$index + '.scenicArea'" :rules="rules.scenicArea">
              <el-input
                v-model="scope.row.scenicArea"
                maxlength="200"
                oninput="if(value.length > 200) value=value.slice(0, 200)"
                placeholder="请输入">
              </el-input>
            </el-form-item>
          </template>
        </el-table-column>
      </el-table>
    </el-form>
    <el-row style="margin-top: 50px">
      <el-col :span="24">
        <el-button type="primary" @click="submit">保存</el-button>
      </el-col>
    </el-row>
  </div>
</template>
<script>
export default {
  name: '',
  props: {},
  components: {},
  data () {
    return {
      formData: {
        name: '',
        age: '',
        tableData: [
          { index: 0, province: '河南', city: '', scenicArea: '' },
          { index: 1, province: '北京', city: '', scenicArea: '' },
          { index: 2, province: '广州', city: '', scenicArea: '' }
        ]
      },
      rules: {
        name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
        age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
        province: [{ required: true, message: '请输入省份', trigger: 'blur' }],
        city: [{ required: true, message: '请输入城市', trigger: 'blur' }],
        scenicArea: [{ required: true, message: '请输入景区', trigger: 'blur' }]
      },
      multipleSelection: [],
      verify: []
    }
  },
  computed: {},
  watch: {},
  created () {},
  mounted () {},
  methods: {
    // 保存
    submit () {
      const f1 = new Promise((resolve, reject) => {
        if (this.multipleSelection.length > 0) {
          resolve('save!')
        } else {
          reject(this.$message.error('请勾选数据'))
        }
      })
      const ary = ['name', 'age']
      // 合并表格中勾选的和上方表单中要校验的字段
      const params = [].concat(this.verify, ary)
      Promise.all([f1]).then(() => {
        const validateFieldList = []
        this.$refs.formRef.validateField(params, isOk => {
          // 部分表单校验时,有几个校验字段就回调几次,isOk空的时候为通过,
          if (!isOk) {
            // 收集每次回调校验的结果等全部回调结束后再判断最终是否全部校验通过
            validateFieldList.push(isOk)
            const flag = validateFieldList.every((item) => item === '')
            // 判断校验的字段数量是否全部校验完且每个结果都是通过则证明最终校验通过
            if (validateFieldList.length === params.length && flag) {
              this.$message.success('保存成功')
            } else {
              return
            }
          }
        })
      })
    },
    // 复选框勾选事件
    handleSelectionChange (val) {
      this.multipleSelection = val
      // 获取表单所有要校验的字段
      const prop = this.$refs.formRef.fields.map(item => item.prop)
      if (val.length <= 0) return this.$refs.formRef.clearValidate(prop)
      this.verify = []
      // 将选中的数据和全部表格中校验的字段遍历 取出勾选对应的校验字段、并将没勾选的校验去除
      this.$refs.formRef.fields.forEach(item => {
        val.forEach(element => {
          if (item.prop.split('.')[1] === element.index.toString()) {
            this.verify.push(item.prop)
          } else {
            this.$refs.formRef.clearValidate(item.prop)
          }
        })
      })
      console.log(this.verify)
      // scope.$index当前行数据在数组中的索引,勾选哪一行校验哪一行的必填项
    },
    // 表头生成必填校验红星样式
    addRedStar (h, { column }) {
      return [
        h('span', { style: 'color: red' }, '*'),
        h('span', ' ' + column.label)
      ]
    }
  }
}
</script>
<style lang='scss' scoped>
</style>

对于 Element UI编辑表格表单校验,你可以使用 Element UI 提供的表单校验规则来实现。 首先,你需要在表单的每个字段定义校验规则。例如,如果要校验一个输入框输入的内容是否为非空字符串,你可以使用 `required` 规则。在编辑表格,你可以通过在表格设置 `rules` 属性来定义校验规则。 下面是一个简单的示例,展示了如何在 Element UI表格使用校验规则: ```html <template> <el-table :data="tableData" style="width: 100%"> <el-table-column label="姓名" prop="name"> <template slot-scope="scope"> <el-form-item :prop="'name.' + scope.$index" :rules="nameRules"> <el-input v-model="scope.row.name"></el-input> </el-form-item> </template> </el-table-column> <el-table-column label="年龄" prop="age"> <template slot-scope="scope"> <el-form-item :prop="'age.' + scope.$index" :rules="ageRules"> <el-input v-model.number="scope.row.age"></el-input> </el-form-item> </template> </el-table-column> </el-table> </template> <script> export default { data() { return { tableData: [ { name: 'John', age: 20 }, { name: 'Jane', age: null }, { name: '', age: 30 } ], nameRules: [ { required: true, message: '请输入姓名', trigger: 'blur' } ], ageRules: [ { required: true, message: '请输入年龄', trigger: 'blur' }, { type: 'number', message: '年龄必须为数字', trigger: 'blur' } ] }; } }; </script> ``` 在上面的示例,我们在姓名和年龄字段的 `el-form-item` 分别设置了校验规则。 `nameRules` 定义了姓名字段的校验规则,要求输入不能为空; `ageRules` 定义了年龄字段的校验规则,要求输入不能为空且必须为数字。 你可以根据实际需求,定义更多的校验规则。除了 `required` 和 `type` 规则之外,还可以使用其他内置的规则或自定义规则来满足你的需求。 当用户在表格编辑数据时,Element UI 会自动触发校验规则,并在不满足规则时显示相应的错误提示信息。你可以根据需求设置校验触发的时机,如 `blur`(失去焦点时触发)、`change`(值发生改变时触发)等。 注意:以上示例是基于 Element UI 2.x 版本的。如果你使用的是 Element Plus,则使用方式类似,只需将组件名换成 `el-input`、`el-table` 等。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值