现在很多库,比如饿了么的element-ui的表单就是用的async-validate实现的表单校验,一般我们是这样的(以vue+element-ui为例)

template

<el -form :model="dataForm" ref="dataForm" :rules="dataFormRules">
    </el><el -form-item label="名称" prop="name">
        </el><el -input v-model="dataForm.name"></el>

        <el -form-item label="版本" prop="version">
        </el><el -input v-model="dataForm.version"></el>


javascript

dataFormRules: {
    name: [
        { required: true, message: '请输入名称', trigger: 'blur' },
        { min: 1, max: 50, message: '长度在 3 到 5 个字符', trigger: 'blur' }
    ],
    version: [
        { required: true, message: '请填写版本', trigger: 'blur' }
    ],
},

其中el-form-item的prop属性要跟dataFormRules里面的对应才行。

当时其实每个el-form-item也可以直接定义自己的rules属性

上面的校验是很常见的,效果也很不错

但是有时我们可能场景比这复杂的多
比如我们要动态添加表单,比如配置文件增删改查参数

原谅我刚才只放了上半部分

这种怎么校验?
我事先并不知道对应的是哪个键值对,顺带讲一下这种用vue怎么实现。首先双向绑定也很显然不可能用类似dataForm.xxx的方式了。后端返回的结果很可能是这样的

{
  "code": 100,
  "msg": null,
  "data": {
    "projectName": "动态注册",
    "envName": "UAT",
    "version": "文件",
    "description": "文件描述",
    "name": "上传文件",
    "list": {
      "client.param": "application",
      "client.param2": "abcde"
    }
  }
}

这是我们只能自己处理下,当然主要是处理list
可以参考这样处理,把list变成这样的类似这样的结构

[
    {keyName:"client.param",keyValue:"application"},
    {keyName:"client.param2",keyValue:"abcde"}
]

这样我们就可以用v-for循环输出了

    <el -form-item v-for="(item,index) in dataForm.keyValues" :key="index">
      </el><el -col :span="3" slot="label">
        </el><el -button
          size="mini"
          type="danger"
          @click="handleDelete(item,index)">删除</el>

      <el -col :span="4" justify="center">键名</el>
      <el -col :span="8">
        </el><el -input label="ok" size="small" v-model="item.keyName">
        </el>

      <el -col :span="4" justify="center">键值</el>
      <el -col :span="8">
        </el><el -input label="ok2" size="small" v-model="item.keyValue">
        </el>


但是这样不够好,我们应该是一个el-input外面对应一个el-form-item
也就是应该用这种

    <el -form-item label="描述" prop="description">
      </el><el -input type="textarea" v-model="dataForm.description"></el>

    <template v-for="(item,index) in dataForm.keyValues">
        <el -button
          size="mini"
          type="danger"
            :key="'btn' + index"
          @click="handleDelete(item,index)">删除
        </el>
      <el -form-item v-for="(item2, index2) in item"
        :rules="rules"
        :prop="'keyValues.' + index + '.index2'"
        :key="index + '-' + index2">
          </el><el -input label="ok" size="small" v-model="item[index2]">
          </el>

    </template>
    <el -form-item>
      </el><el -button type="info" @click="handleAdd">新增参数</el>

const check = (rules,value,callback)=>{
  console.log('value', value)
}


data(){
    return{
        rules:[{
            validator: check, trigger:'blur'
        }],
    }
}

我们希望的是在input框移出的时候进行一些校验,就是上面的check函数,如果一切顺利的话,第二个参数value的值就应该是输入的值,然后我们就可以运用正则之类的进行处理了,但是上面的代码还是有点问题的,check方法里面输出的value是undefined,但是程序没有报错啊。

问题就出在

:prop="'keyValues.' + index + '.index2'"

我们先随意将其改成错误的,让程序报错,方便我调试定位

:prop="'keyValues' + index + '.index2fdfad'"

报错如下:Error in event handler for "el.form.blur": "Error: please transfer a valid prop path to form item!"

我们一步一步定位,定位到util.js?ca50:65上面

65行报的错,我们会发现path=keyValues0.index2fdfad并且path会两次正则替换,第一个是获取中括号[]里面的内容,第二个是将.替换掉。
实际上它的最终目的是要变成获取keyValues[0][index2]的值,简单说明下

keyValues = [
    {keyName:"client.param",keyValue:"application"},
    {keyName:"client.param2",keyValue:"abcde"}
]

index2 = keyName
index2 = keyValue

了解了套路我们就可以依次作为依据改props

:prop="'keyValues.' + index + '.' + index2"

现在我们就可以根据获取的值进行校验了

const check = (rules,value,callback)=>{
  console.log('value', value)
  if(!value === 'abc'){
    callback('输入的不是abc');
  }else{
    callback();
  }
}
分类: Javascript

8 条评论

普若木特 · 2018/05/17 20:47

@冰, 解决了问题就好

言西早小姐 · 2018/05/10 11:11

规格名有一个,规格值却有多个,我在这过程遇到的问题是规格名为空的时候会有校验提示,但是规格名不为空但规格值为空的情况下却没校验提示,这个问题我思考了好久还是没找到答案,希望大神指教下,谢谢哈

普若木特 回复:

@言西早小姐, 大致明白你的意思,但是不确定,如果可以的话看下代码最好。

tonX · 2018/04/27 16:35

很棒棒的~解决了我的问题:)
想起了前刚用VUE的时候通过V-for实现动态生成组件,然后又苦恼无法对每个生成的组件进行管理,然后自己就给每个组件加上了个ID的方法...这里有异曲同工之妙呢.

普若木特 回复:

@tonX, 这是我的荣幸

普若木特 · 2018/04/25 22:26

@冰, 主要自己要耐心打下断点就能发现它的规则,简单的说,对于能确定名字的就用字符串,对象变量(比如这里可能是keyName或者keyValue,并不确定)就直接用变量,用+拼接,但是需要注意的是如果两个都是变量时不能直接用+相加,已经用字符串param1 + '.' + param2进行相加,这也是看到源码里面用到了.才知道的

回复:

@普若木特, 谢谢!

· 2018/04/25 21:59

:prop这个地方还是不太好发现的,我之前做的项目也是自定义校验函数,但是不是报错,就是取不到值,学习了,搞定了我的问题,谢谢!

发表评论