前言:
form 表单验证是几乎所有 web 项目或者 APP 都会遇到的,这是非常常用也是非常重要的一项知识,这里我们简单学习一下表单验证的方法。
async-validator
是一个表单的异步验证的第三方库,它是 https://github.com/tmpfs/async-validate 的演变。也是 element-ui 中的 form 组件所使用的验证方式。
我们就仿写一个 element-UI 的表单验证功能。
安装插件
我首先还是使用了 vue 脚手架,因为表单验证,我们使用了 async-validator
所以这里我们要先安装一下这个第三方库
1
| npm install --save async-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 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <template> <div id="app"> <h3>Element表单</h3> <hr /> <!-- 在最外层对model和rules进行数据绑定 --> <el-form :model="model" :rules="rules" ref="loginForm"> <el-form-item label="用户名" prop="username"> <!-- v-model把可以看作:value 和 @input的语法糖 把model.username作为value传入 --> <el-input v-model="model.username"></el-input> </el-form-item> <el-form-item label="确认密码" prop="password"> <el-input type="password" v-model="model.password"></el-input> </el-form-item> <el-form-item> <button type="primary" @click="submitForm('loginForm')">提交</button> </el-form-item> </el-form> </div> </template> <script> import ElInput from './components/ElInput.vue' import ElForm from './components/ElForm' import ElFormItem from './components/ElFormItem' export default { name: 'App', components: { ElInput, ElForm, ElFormItem, }, data() { return { model: { username: '', password: '' }, // 校验规则 rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, ], password: [{ required: true, message: '请输入密码', trigger: 'blur' }], }, } }, } </script> <style></style>
|
- 然后
ElForm
组件 ,我们接收 App
组件传来的值,并进行 provide。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <template> <form> <slot></slot> </form> </template> <script> export default { name: 'ElForm', provide() { return { form: this, } }, // 接收App传来的数据 props: ['model', 'rules'], } </script> <style scoped></style>
|
- 然后是
ElInput
组件,非常简单的的一个功能,实现双向绑定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!-- 绑定value属性 使用的是父组件传入的参数 实现input事件 派发事件 固定写法 --> <template> <input :type="type" :value="value" @input="onInput" @blur="onBlur" /> </template> <script> export default { name: 'ElInput', // 接受父组件传来的值 props: { value: { type: String, default: '', }, type: { type: String, default: 'text', }, }, } </script> <style scoped></style>
|
- 然后在
ELFormItem
组件中设置插槽,插入我们的 ElInput
组件,展示我们的错误信息:
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
| <template> <div> <!-- 父组件传值 --> <label v-if="label">{{ label }}</label> <slot></slot> <!-- 错误信息 是自身的属性 --> <p v-if="error" style="color:red">{{ errortext }}</p> </div> </template> <script> import Schema from 'async-validator' export default { name: 'ElFormItem', // 注入数据 inject: ['form'], // 接收参数 props:['label', 'prop'], data() { return { errortext: '', error: false } } </script> <style scoped></style>
|
这样我们的基本结构就搭建好了。
实现逻辑
- 首先我们在
ElInput
组件中派发事件,这里我们使用 $dispatch
,所以要先在 main.js
中添加该方法:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false Vue.prototype.$dispatch = function (eventName, data) { let parent = this.$parent while (parent) { parent.$emit(eventName, data) parent = parent.$parent } } new Vue({ render: (h) => h(App), }).$mount('#app')
|
- 然后我们就可以在
ElInput
组件中派发事件:
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
| <template> <input :type="type" :value="value" @input="onInput" @blur="onBlur" /> </template> <script> export default { name: 'ElInput', props: { value: { type: String, default: '', }, type: { type: String, default: 'text', }, }, methods: { onInput(e) { // 派发消息input 和 输入框的值作为参数 this.$emit('input', e.target.value) // 通知校验 this.$dispatch('validate') }, }, } </script> <style scoped></style>
|
- 首先我们在
ElFormItem
组件中进行校验。
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
| <template> <div> <label v-if="label"> {{ label }} </label> <slot></slot> <p v-if="error" style="color:red">{{ errortext }}</p> </div> </template> <script> // 引入第三方库 import Schema from 'async-validator' export default { name: 'ElFormItem', inject: ['form'], props: ['label', 'prop'], data() { return { errortext: '', error: false, } }, methods: { //当输入时 子类通过$parent派发的 本身负责接收然后 校验 validate() { // 获取rules,校验规则 const rules = this.form.rules[this.prop] // 获取数据模型 const value = this.form.model[this.prop] // 定义一个descriptor let desciptor = { [this.prop]: rules } const schema = new Schema(desciptor) //返回的是promise return schema.validate({ [this.prop]: value }, (errors) => { if (errors) { this.errortext = errors[0].message this.error = true } else { this.errortext = '' this.error = false } }) }, }, mounted() { this.$on('validate', this.validate) }, } </script> <style scoped></style>
|
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
| <template> <form> <slot></slot> </form> </template> <script> export default { name: 'ElForm', provide() { return { form: this, } }, props: ['model', 'rules'], methods: { //做全局校验 cb是传进来的函数 validate(cb) { //获取校验项 //首先拿到KForm的子元素 拿去遍历 得到的是每一个FormItem 让它执行validate方法 //返回的是一个promise数组 const tasks = this.$children .filter((item) => item.prop) .map((item) => item.validate()) //Promise.all所有promise成功才算成功 Promise.all(tasks) .then(() => cb(true)) .catch(() => cb(false)) }, }, } </script> <style scoped></style>
|
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
| <template> <div id="app"> <h3>Element表单</h3> <hr /> <el-form :model="model" :rules="rules" ref="loginForm"> <el-form-item label="用户名" prop="username"> <el-input v-model="model.username"></el-input> </el-form-item> <el-form-item label="确认密码" prop="password"> <el-input type="password" v-model="model.password" autocomplete="off" ></el-input> </el-form-item> <el-form-item> <button type="primary" @click="submitForm('loginForm')">提交</button> </el-form-item> </el-form> </div> </template> <script> import ElInput from './components/ElInput.vue' import ElForm from './components/ElForm' import ElFormItem from './components/ElFormItem' export default { name: 'App', components: { ElInput, ElForm, ElFormItem, }, data() { return { model: { username: '', password: '' }, rules: { username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, ], password: [{ required: true, message: '请输入密码', trigger: 'blur' }], }, } }, methods: { submitForm(formName) { this.$refs[formName].validate((valid) => { if (valid) { alert('校验成功') } else { alert('校验失败') } }) }, }, } </script> <style></style>
|
结语:
一个简单的表单验证功能就完成了,这里面有很多都是第三方库的知识,很多都是一个固定的写法,你可以查看一下参考资料,进行一个详细的学习。
参考资料:
Element-UI 表单:https://element.eleme.cn/#/zh-CN/component/form
校验规则:https://github.com/yiminghe/async-validator