vue表单验证

  • 邢毅彪
  • 16 Minutes
  • 2018年7月14日

前言

在前端应用开发中, 表单验证是比较常见的需求。接触过angular的开发者可能会对angular的表单验证印象深刻,并比较推崇。但是在vue这种渐进式,轻量化的框架里面,是否也可以实现比较友好的表单验证呢? 答案是肯定的。本次会介绍两种表单验证方式:基于elementUI的表单组件的表单验证和基于vue-form的表单验证。

直接上干货

  1. 基于elementui的表单验证
    在国内的vue开发者中,elementUI的使用率相当广泛,当然我个人也是elementUI的使用者之一,本次先说基于elementui的表单验证。
    1.1. 安装elementUI并引入elementUI
1
yarn add element-ui
1
2
3
4
5
6
7
// main.ts
import Vue from 'vue'
import ElementUI from 'element-ui'

import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

1.2. 使用elementUI的表单验证
使用elementUI就比较简单了,
可以参考官方文档,这里只简述一下基本使用方法, 更加全面的api及使用可以参考elementUI-form

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<template>
<div class="hello">
<p>elment-ui表单</p>
<el-form :model="formState" :rules="rules" status-icon ref="eleForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="formState.username"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="formState.password"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="repassword">
<el-input v-model="formState.repassword"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm()">提交</el-button>
</el-form-item>
</el-form>
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class elementForm extends Vue {
public name: string = 'elementForm'

// 表单状态
public formState = {
username: '',
password: '',
repassword: '',
}

// 表单校验规则
public rules = {
username: [
{
required: true,
message: '请输入用户名',
trigger: 'change',
},
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur',
},
],
repassword: [
{
validator: this.passwordEqu,
trigger: 'change',
},
],
}

// 自定义校验规则
private passwordEqu(rule: any, value: string, cb: (err?: Error) => void) {
if (value === '') {
cb(new Error('请再次输入密码'))
} else if (value !== this.formState.password) {
cb(new Error('两次密码不一致'))
} else {
cb()
}
}

// 点击提交表单
public submitForm() {
(this.$refs.eleForm as any).validate((valid: boolean, msg: object) => {
if (valid) {
this.$message.success('验证通过')
} else {
console.log(msg)
this.$message.error('请检查表单数据')
}
})
}
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>

其中el-form上model属性对应的是表单的数据对象,rules对应的是表单的验证规则,status-icon则在表单验证过程中可以将验证状态以icon的方式显示在表单空间的右侧.
表单验证规则是一个对象,其中包括每个表单空间的key,对应模板里每个item的prop,验证规则是一个数组,即可以单个控件有多个验证规则,其中message是验证不通过的提示信息,trigger则是验证触发的方法,有change和blur等几种触发事件,亦可以传入数组表示多触发条件.
这里有演示到同步自定义验证器,验证器会回调三个参数,分别是rule,value,cb,其中value为验证器触发时当前控件的值,cb为验证是否通过的回调,当验证不通过是接受一个error对象,这时会对应验证不通过的提示,当验证通过时应当直接调用cb方法(源码在此处会校验,如果是undefined则会认为校验通过,如果按照nodejs规则传入null,则会视为校验不通过,此应为api设计缺陷)
验证器同时支持异步验证,可以在promise或者其他异步事件之后显示调用cb方法。(验证规则可以参考async-validator, elementUI表单验证基于此开发)

1.3。 提交时验证表单是否可以提交
正如大多数表单验证需求一样, 输入时表单验证是为了更好的用户体验,用户更早的发现表单输入错误,而提交时的表单验证亦是不可或缺的。
首先用vue自由的ref获得form表单的引用,其次通过elementUI为其提供的validate方法进行验证,validate方法接受一个回调函数,在回调函数里会传入两个参数,第一个参数是表单是否验证通过,第二个参数为验证对象的详情。通常我们会先判断第一个参数用来验证是否可以提交表单,第二个参数用来判断用户未验证通过的原因,以提醒用户。至此elementUI的表单验证基本介绍到这里。

  1. vue-form表单验证
    vue-form在易用性及对ts的支持上不如elementUI友好,但是其提供了一种类似于angular表单使用习惯的验证方法,这里只是作为举例。

2.1. 安装vue-form

1
yarn add vue-form

2.2. 编写type文件
vue-form官方并没有提供type文件,因此我们直接引入ts环境的vue会直接报错(js环境请无视这步配置)

1
2
3
4
5
// vue-form.d.ts
declare module 'vue-form' {
import Vue from "vue";
export default class VueForm extends Vue {}
}

2.3. 引入vue-form
vue-form支持两种引入方式,一种是全局use,第二种是mixins局部引入,由于自定义验证器要在引入时要声明,所以建议使用局部mixins引入,引入及使用如下

<template>
  <div class="vue-form">
    <vue-form :state="formState" @submit.prevent="onSubmit">
      <validate tag="label">
        <span>用户名</span>
        <input v-model="model.username" required name="username" />
        <field-messages name="username">
          <span>Success</span>
          <template slot="required" slot-scope="state">
            <span v-if="state.$dirty || state.$submitted">请输入用户名</span>
          </template>
        </field-messages>
      </validate>
      <validate tag="label">
        <span>密码</span>
        <input v-model="model.password" required name="password" />
        <field-messages name="password">
          <div>Success!</div>
          <template slot="required" slot-scope="state">
            <span v-if="state.$dirty || state.$submitted">请输入密码</span>
          </template>
        </field-messages>
      </validate>
      <validate tag="label">
        <span>用户名</span>
        <input v-model="model.repassword" required name="repassword" />

        <field-messages name="repassword">
          <div>Success!</div>
          <template slot="required" slot-scope="state">
            <span v-if="state.$dirty || state.$submitted">请确认密码</span>
          </template>
        </field-messages>
      </validate>
      <button type="submit">Submit</button>
    </vue-form>
  </div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { mixins } from 'vue-class-component'
import VueForm from 'vue-form'

@Component
export default class VueFormVal extends mixins(VueForm) {
  // 表单状态
  public formState: any = {}

  // 表单值
  public model = {
    username: '',
    password: '',
    repassword: '',
  }

  public onSubmit() {
    if (!this.formState.$invalid) { // 表单验证通过
      // TODO xxx
    } else { // 表单验证不通过
      console.log(this.formState)
    }
  }
}
</script>
<style lang="scss" scoped>

</style>

在模板处建议使用自定义模板,一是定制性强,二是可以类似angular自定义显示提示文字的时机。这里的表单状态与angular类似。

2.4. 同上面elementUI表单验证时所讲,表单往往在提交表单时会有验证的需求和必要,此处vue-form建议我们直接拦截原生的submit事件,在拦截之后,我们可以根据formState的属性进行判断,formState的$invalid属性返回一个boolean值用以展示表单验证是否通过,我们的所有的表单字段会直接挂在在这个状态对象上,每个对象也有$invalid属性,对应各自控件的状态。

总结

在我短暂的使用过程中, vue在表单验证这块,一没有官方的实现,二社区实现方案(vue-form或elementUI)过于简陋,只能满足简单的表单校验需求,而且无论在交互上还是编程感官上,都差一点。期待后期会有比较成熟的官方或者社区实现,vue的普及势必会在后台管理或者oa等项目上大量使用,而表单这块vue只提供了v-model还是过于简陋。

访问量