el-form使用数组渲染遍历验证

229 阅读1分钟
<el-form
    ref="form"
    :model="form"
    :rules="rules"
    style="position: relative; width: 100%"
    class="demo-ruleForm"
  >
    <!-- <span style="color: #f56c6c; position: absolute; z-index: 2; left: 60px; top: 7px">
      value必填,并且只能为正整数
    </span> -->
    <el-table
      :data="form.dataSource"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      border
      default-expand-all
      row-key="uid"
      :header-cell-style="{ background: '#E8ECFF', height: '40px', padding: '0' }"
      :cell-style="{ height: '40px', padding: '0' }"
    >
      <!-- label-class-name="is-require" -->
      <el-table-column label="name" prop="name" width="400">
        <template #default="{ row }">
          <el-form-item
            :class="errorsUid.includes(row.uid) ? 'is-error' : ''"
            :prop="_createFormProp(row, 'name')"
            :rules="rules.name"
          >
            <el-input v-model="row.name" />
          </el-form-item>
        </template>
      </el-table-column>
</el-form>  
data(){
const validateName = (rule, value, callback) => {
    if (!value) {
    return callback(new Error('请输入name'));
    }
    let fullField = rule.fullField.split('.');
    let currentIndex = fullField.splice(0, fullField.length - 1).join('.');
    let ruleList = JSON.parse(JSON.stringify(this.form)); //eval不能使用vue上的this属性
    let currentObj = eval('ruleList.' + currentIndex);
    //校验输入数据是否存在重复
    callback();
    };
 }
 
 return {
         rules: {
            name: [
              { required: true, message: '请输入name', trigger: 'blur' },
              { required: true, message: '请输入name', trigger: 'change' },
              { validator: validateName, trigger: 'blur' },
            ],
      },
 }
 }
 methods: {
    _createFormProp(row, key) {
      //遍历寻找下标
      let currentRow = this.getIndexByUid(this.form.dataSource, row.uid);
      let topIndex = currentRow[0].index;
      let childIndexs = '';
      if (currentRow.length > 1) {
        //是子元素
        childIndexs = currentRow.splice(1).reduce((total, cur) => total + '.children[' + cur.index + ']', '');
        // console.log('结果为', 'dataSource.' + topIndex + childIndexs +  '.' + key);
        return 'dataSource[' + topIndex + ']' + childIndexs + '.' + key;
      }
      return 'dataSource[' + topIndex + '].' + key;
    }, 
    //根据uid获取所有层级的index
    getIndexByUid(arr, uid) {
      let target = [];
      for (let i = 0; i < arr.length; i++) {
        let item = arr[i];
        let tempObj = {
          uid: item.uid,
          index: i,
        };
        if (item.uid == uid) {
          target.push(tempObj);
          break;
        }
        if (item.children.length > 0) {
          let list = this.getIndexByUid(item.children, uid);
          if (list.length > 0) {
            target = target.concat(tempObj, list);
          }
        }
      }
      return target;
    },
 }

  • prop使用dataSource[0].children[1].name等形式来嵌套绑定。
  • 然后在rules进行验证的时候传递过去的rule.fullField会完整的包含prop的值,即类似dataSource[0].children[1].name的值。因为该值为字符串直接使用js会当作key值进行解析,因此我们需要将字符串来转换为变量eval,而eval的值不能为this点出来的,需要重新用变量再进行操作。