前言:element-ui 的表单用起来实在是太僵硬了,组长便让我去看一看VeeValidate的表单验证系统,粗略看了一下官方文档,确实要灵活好用很多,便在此记录一下用法

特点

  • 无需使用v-model将input与变量绑定(但想的话也可以),而是使用v-bind与对应的field绑定。最后直接通过form的value读取。

💡 导入
npm install --save vee-validate@next
import { Form, Field, ErrorMessage } from 'vee-validate';

官方文档:VeeValidate: Painless Vue.js forms (logaretm.com)

基础用法示例

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
<script lang="ts" setup>
import { Form, Field, ErrorMessage } from 'vee-validate';

const validateEmail = (value: any) => {
return /@/.test(value) ? true : '邮箱格式错误'
}

const isRequired=(value:string)=> {
if (value && value.trim()) {
return true;
}
return '你没通过捏';
}

const onSubmit = (values) => {
//values是一个对象,存有填好的表单的值,key是元素的name。
console.log(values)
alert('验证通过时执行')
}

</script>
<template>
<!-- <Form>包裹整个表单,<Field>包裹表单中的一个字段 -->
<!-- @submit在所有Field都返回true时才触发 -->
<Form @submit="onSubmit">
<Field name="username" :rules="isRequired" :validate-on-input="true" #default="{ errorMessage, field }">
<!-- field来自<Field>的v-slot, 意味着值的绑定与事件的绑定。在数据不方便双向绑定,如file时,或想自己配置绑定事件时不使用v-bind写法,具体请看官方文档 -->
<input v-bind="field" type="text" />
<!-- errMessage即为校验失败后显示的信息 -->
<p>{{ errorMessage }}</p>
</Field>

<!-- onsubmit会监听内部每一个button的点击,点击时触发内部所有Field的验证 -->
<button>提交</button>
<button>提交</button>
</Form>
</template>

使用自定义输入框

1
2
3
4
5
6
<Form>
<Field name="username" :rules="{ email: true }" #default="{ errorMessage, value }">
//自定义组件推荐使用update:modelValue事件实现与Field的绑定
<CustomInput :modelValue="value" @update:modelValue="handleChange" />
</Field>
</Form>

验证规则绑定

声明验证规则

验证规则有两种,一是直接使用函数,还有一种叫validator(个人感觉和函数区别也不大)

使用函数

声明一个函数,返回值是 bool或string 。return true 时errormessage为空, return false则errormessage为默认值, return string 则将该string赋值给errormessage。

1
2
3
4
5
6
const isRequired = (value) => {
if (value && value.trim()) {
return true;
}
return 'This is required';
}

之后使用:rules绑定

<Field name="field" :rules="isRequired" />

使用validator

声明一个validator, 类似函数

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
import { defineRule } from 'vee-validate';
defineRule('required', (value :string) => {
if (!value || !value.length) {
return 'This field is required';
}
return true;
});
//需要参数的validator
defineRule('minLength', (value, [limit]) => {
// The field is empty so it should pass
if (!value || !value.length) {
return true;
}
if (value.length < limit) {
return `This field must be at least ${limit} characters`;
}
return true;
});
defineRule('minMax', (value, [min, max]) => {
// The field is empty so it should pass
if (!value || !value.length) {
return true;
}
if (value.length < min) {
return `This field must be at least ${min} characters`;
}
if (value.length > max) {
return `This field must be at most ${max} characters`;
}
return true;
});

而后用:rules绑定

绑定单个<Field name="username3" :rules="'resquired'" >

绑定多个<Field name="username3" :rules="'resquired|email'" >

绑定带参数的validator <Field name="username3" :rules="'resquired|minLength:8'" >

绑定带多个参数的validator <Field name="username3" :rules="'minMax:5,8|resquired'" >

绑定规则

除每个field单独绑定外,还可定义一个schema控制所有rules后通过name分配rule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<!-- 给Form绑定schema -->
<Form @submit="submit" :validation-schema="schema" v-slot="{ errors }">
<Field name="email" />
<span>{{ errors.email }}</span>
<Field name="password" type="password" />
<span>{{ errors.password }}</span>
<button>Submit</button>
</Form>
</template>
<script setup>
import { Form, Field } from 'vee-validate';
const schema = {
email: 'required|email',
password: 'required|minLength:8',
};
</script>

验证时机的设置

单一Field验证:

1
2
3
4
5
<Field name="username" :rules="{ email: true }" :validateOnInput="true" #default="{ errorMessage, field }">
<input v-bind="field" type="text" />
<p>{{ errorMessage }}</p>
<button></button>
</Field>
与时机有关的prop 默认值 介绍
validateOnMount false
validateOnInput false
validateOnChange true
validateOnBlur true
validateOnModelUpdate true
bails true 绑定多个验证规则时,有一个验证规则未通过,直接结束验证,而不再继续验证其他规则

全表验证:

除最后的提交之外,可能还有其他地方也需要进行全表验证,VeeValidate为此提供了validate模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<!-- 导入validate模块 -->
<Form @submit="onSubmit" #default="{ validate }">
<Field name="username1" :rules="isRequired" #default="{ errorMessage, field}">
<input v-bind="field" type="text" />
<p>{{ errorMessage }}</p>
</Field>
<Field name="username2" :rules="isRequired" #default="{ errorMessage, field }">
<input v-bind="field" type="text" />
<p>{{ errorMessage }}</p>
</Field>
<!-- 使用validate模块 -->
<div @click="validate()">11111</div>
</Form>
</template>

状态管理(trigger)

Form

1
2
3
4
5
6
7
8
9
10
<!-- 验证状态管理 -->
<Form @submit="onSubmit" #default="{ meta }">
<div>{{ meta }}</div>
</Form>
//渲染结果{ "initialValues": {}, "touched": false, "pending": false, "valid": false, "dirty": false }
meta.value.initialValues; //一个对象,包含所有字段的初始值,key是字段的name
meta.value.touched;//是否有字段被focus过,并且已经blur
meta.value.pending; //是否有字段还在验证中
meta.value.valid; //是否全部通过验证
meta.value.dirty; //是否有字段更新
1
2
3
<!-- 提交状态管理 -->
<!-- isSubmitting在提交时值为true,提交完成后值变为false -->
<v-form :validation-schema="schema" @submit="onSubmit" v-slot="{ isSubmitting }">

Field

1
2
3
4
5
<Field name="email" type="email" :rules="validateEmail" v-slot="{ field, meta }">
<input v-bind="field" />
<pre>{{ meta }}</pre>
<!--渲染出的结果为{ "touched": true, "pending": false, "valid": false, "validated": false, "dirty": true }-->
</Field>

表单的提交

You will rarely need to access the form values inside the template, but it is there if you ever need it. What’s interesting is that vee-validate follows the assumption that most likely you will need the form values at the submission phase.
您很少需要在提交这一步骤之外使用表单值,基于这个假设,vee-validate只在提交阶段提供表单值。但如果您有需要,请额外使用v-model绑定你想要的元素

⬆️源自VeeValidate官方文档

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
<script lang="ts" setup>
import { Form, Field, ErrorMessage} from 'vee-validate';
//values为表单内部的值,是一个对象,key为field的name
const onSubmit = (values) => {
console.log(values);
}
//value为用户填入的值,results存有验证是否通过的信息,errors为错误信息
const onInvalidSubmit=({values, errors, results})=>{
console.log(values);
console.log(errors);
console.log(results);
}
const isRequired=(value:string)=> {
if (value && value.trim()) {
return true;
}
return '你没通过捏';
}
</script>
<template>
<!-- 在所有验证都通过时触发submit事件,其handler默认带表单值为参数。有验证不通过时触发invalid
Submit事件 -->
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit">
<Field name="username1" :rules="isRequired" #default="{ field}">
<input v-bind="field" type="text" />
</Field>
<Field name="username2" :rules="isRequired" #default="{ errorMessage, field }">
<input v-bind="field" type="text" />
<p>{{ errorMessage }}</p>
</Field>
<!-- Form自动监听其间button的点击事件,点击则对所有field进行验证 -->
<button>一个按钮</button>
</Form>
</template>

杂项

绑定初始值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 仍可以使用v-model来绑定初始值 -->
<script lang="ts" setup>
...
<!-- 定义初始值 -->
const formValues ={
username1:'test1',
username2:'test2',
}
</script>
<template>
<!-- 给Form绑定initialValues -->
<Form @submit="onSubmit" :initialValues="formValues" >
<Field name="username1" :rules="isRequired" #default="{ errorMessage, field}">
<input v-bind="field" type="text" />
<p>{{ errorMessage }}</p>
</Field>
<Field name="username2" :rules="isRequired" #default="{ errorMessage, field }">
<input v-bind="field" type="text" />
<p>{{ errorMessage }}</p>
</Field>
<button>1212</button>
</Form>
</template>

错误信息的显示

<*ErrorMessage* *name*="field" *as*="div" />

可以通过修改as的值,将错误信息改为自定义组件

更改值

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
<!-- 行内函数更改 -->
<Form v-slot="{ setFieldValue, setValues }">
<Field name="email" />
<ErrorMessage name="email" />
<Field name="password" />
<ErrorMessage name="password" />
<button type="button" @click="setFieldValue('email', 'test')">Set Field Value</button>
<button type="button" @click="setValues({ email: 'test', password: 'test12' })">
Set Multiple Values
</button>
</Form>

<!-- js中使用 ---------------------------------------------------------------------->

<script lang="ts" setup>
...
const numval = ref(5)
<!--获取ref-->
const myForm = ref()
<!-- 更改一个值 -->
function changevalue(){
myForm.value.setFieldValue('username1',numval.value++)
}
<!-- 更改多个值 -->
function changevalues(){
myForm.value.setValues(
{
username1: 1,
username2: 2
}
)
}
</script>

<template>
<!-- 获取ref -->
<Form @submit="onSubmit" ref="myForm" >
<Field name="username1" #default="{ errorMessage, field}">
<input v-bind="field" type="number" />
<p>{{ errorMessage }}</p>
</Field>
<Field name="username2" #default="{ errorMessage, field }">
<input v-bind="field" type="number" />
<p>{{ errorMessage }}</p>
</Field>
<div @click="changevalue">111</div>
<div @click="changevalues">222</div>
</Form>
</template>