之前已经讲过一个关于el-form的校验的文章《 element-ui动态表单async-validate校验 please transfer a valid prop path to form item!》,表单的校验依然是async-validate实现的。
目前在项目中使用到的表格很多时候比表单还多,以前表格是自己写的校验,这样一般是在点击提交按钮时会触发校验,代码一般是这样的。

listData: [
          {
            salePriceErr: '',
            salePrice: 1,
            listPriceErr: '',
            listPrice: 2,
            courseErr: '',
            course: 'Math',
          },{
            salePriceErr: '',
            salePrice: 2,
            listPriceErr: '',
            listPrice: 8,
            courseErr: '',
            course: 'CS',
          }]
<el-table :data="listData">
  <el-table-column label="salePrice" prop="salePrice">
    <template slot-scope="scope">
      <el-input-number v-model="scope.row.salePrice"></el-input-number>
      <p v-if="scope.row.salePriceErr">{{scope.row.salePriceErr}}</p>
    </template>
  </el-table-column>
  <el-table-column label="listPrice" prop="listPrice">
    <template slot-scope="scope">
      <el-input-number v-model="scope.row.listPrice"></el-input-number>
      <p v-if="scope.row.listPriceErr">{{scope.row.listPriceErr}}</p>
    </template>
  </el-table-column>
  <el-table-column label="listPrice" prop="listPrice">
    <template slot-scope="scope">
      <el-button @click="save(scope)"></el-button>
    </template>
  </el-table-column>
</el-talbe>

这种我们一般在点击是在save方法里面先校验。这样的缺点很明显:
1. 我们需要预设一些字段,比如salePriceErr, listPriceErr等,这些字段后端肯定不会返回啊,我们在listData里面需要额外加上,并且我们一般需要使用$set来添加这些字段已确保它们是响应式的。并且这种事提前知道有salePrice或者listPrice字段的,如果有个数组,那样里面有多少字段也是无法预知的,就不好提前预设了。

listData: [
{
  salePrice: 1,
  listPrice: 2,
  course: 'Math',
  users: [
  {
    studentNO: '001',
    name: 'zhangsan',
    scores: 122
  }, {
    studentNO: '002',
    name: 'lisi',
    scores: 107
  }]
}, {
  salePrice: 2,
  listPrice: 5,
  course: 'English',
  users: [
  {
    studentNO: '001',
    name: 'zhangsan',
    scores: 87
  }, {
    studentNO: '002',
    name: 'lisi',
    scores: 97
  }]
}]

如果我们要校验users里面的信息就不好预设xxxErr

关于如何动态加载数组users里面的数据可以参考《el-table实现动态列el-table-column

  1. 我们的校验需要在用户点击了按钮之后才回触发save方法,如果校验出现了不合法输入的提示,不再次触发校验的话那些提示不会自动消失,用户体验不好。

如果能像表单校验的话就不存在上述问题。
我们可以试着把el-table和el-form结合起来使用(部分代码从简)

<el-form>
  <el-table :data="listData">
    <el-table-column label="salePrice" prop="salePrice">
      <template slot-scope="scope">
        <el-form-item>
          <el-input-number v-model="scope.row.salePrice"></el-input-number>
          <p v-if="scope.row.salePriceErr">{{scope.row.salePriceErr}}</p>
        </el-form-item>
      </template>
    </el-table-column>
    <el-table-column label="listPrice" prop="listPrice">
      <template slot-scope="scope">
        <el-form-item>
          <el-button @click="save(scope)"></el-button>
        </el-form-item>
      </template>
    </el-table-column>
  </el-talbe>
</el-form>

使用过el-form校验的都知道,它有属性modelrules,其中model是对象、rules也是对象,每个el-form-item需要prop来配合。
所以我们可以”改装”下数据

model: {
  listData: [{
    salePrice: 1,
    listPrice: 2,
    course: 'Math',
  }]
},
<el-form :model="model">
  <el-table :data="model.listData">
  <el-table-column v-for="(item, index) in obj.listData[0].users">
      <template slot="header" slot-scope="scope">
        {{item.name}}
      </template>
      <template slot-scope="scope">
        <el-form-item :prop="'listData.' + scope.$index + '.users.' + index + '.scores'" :rules="rules.scores">
          <el-input-number v-model="item.scores"></el-input-number>
        </el-form-item>
      </template>
    </el-table-column>
    <el-table-column label="salePrice" prop="salePrice" :rules="rules.salePrice">
      <template slot-scope="scope">
        <el-form-item>
          <el-input-number v-model="scope.row.salePrice"></el-input-number>
          <p v-if="scope.row.salePriceErr">{{scope.row.salePriceErr}}</p>
        </el-form-item>
      </template>
    </el-table-column>
    <el-table-column label="操作">
      <template slot-scope="scope">
        <el-form-item>
          <el-button @click="save(scope)"></el-button>
        </el-form-item>
      </template>
    </el-table-column>
  </el-table>
</el-form>
rules: {
  salePrice: {
    validator(rules, value, callback){
      if(value) {
        callback();
      }else {
        callback('不能为空')
      }
    }
  },
  scores: {
    validator(rules, value, callback){
      if(value) {
        callback();
      }else {
        callback('不能为空')
      }
    }
  },
}

这里的rules是直接用在el-form-item上面的,尤其是像scores这种,放在el-form-item上更加方便些
大家可能注意到prop上貌似写的比较复杂
这种写法主要是为了遵循async-validate的规则,代码如下:

function getPropByPath(obj, path, strict) {
  var tempObj = obj;
  path = path.replace(/\[(\w+)\]/g, '.$1');
  path = path.replace(/^\./, '');

  var keyArr = path.split('.');
  var i = 0;
  for (var len = keyArr.length; i < len - 1; ++i) {
    if (!tempObj && !strict) break;
    var key = keyArr[i];
    if (key in tempObj) {
      tempObj = tempObj[key];
    } else {
      if (strict) {
        throw new Error('please transfer a valid prop path to form item!');
      }
      break;
    }
  }
  return {
    o: tempObj,
    k: keyArr[i],
    v: tempObj ? tempObj[keyArr[i]] : null
  };
};

所以上面的:prop="'listData.' + scope.$index + '.users.' + index + '.scores'"就可以实际上获取到的就是
this.obj.listData[0].users[0].scores的值了,当然,里面[0]的0是会变的。

关于async-validate也可以参考element-ui动态表单async-validate校验 please transfer a valid prop path to form item!

算了,今天就写这么多吧,改天有时间再写。
对上面写的有疑问欢迎大家一起探讨。


发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据