2 form表单校验
- 整体思路:
form.vue组件包含rules、fieldList,formItem.vue组件包含filename,label,input.vue包含value,将input.vue组件中的input,blur, foucs事件emit到formItem.vue组件中,form.vue中的rules.name对象与filename相对应,所有的校验都在formItem中判断。
2.Form组件
-
Form组件作为最外层容器,需要将rules规则和fieldList带入,在created生命周期中获取所有子实例FromItemrules: { username: [ { require: true, message: '用户名不能为空', trigger: 'blur' }, ], email: [ { require: true, message: '邮箱不能为空', trigger: 'blur' }, { type: 'email', message: '邮箱格式不正确', trigger: 'blur' } ] }, filedList: { name: '', email: '' } -
组件基本结构,
slot<template> <div class="form"> <slot></slot> </div> </template>
-
FormItem组件<template> <div class="form-item"> <label v-if="label" :class="{'label-red': isRequire}">{{ label }}</label> <slot></slot> <p v-show="errTip" style="color: red">{{ errTip }}</p> </div> </template>- 需要监听
input组件的实时变化,blur失去焦点时需要校验,focus需要将错误的提示信息去掉, - 需要获取
Form组件的data值,获取相对应的规则this.parentRules = this.$parent.rules[this.filename] || [];
- 需要监听
-
input组件<template> <input type="text" :value="currentValue" @input="handleInput" @blur="handleBlur" @focus="handleFocus" > </template>- 结合语法糖
v-model,将数据通过$emit上发,this.$parent.$emit('onFoucsInput') // 失去焦点时校验
- 结合语法糖
-
完整的组件代码
input
<template> <input type="text" :value="currentValue" @input="handleChange" @blur="handleBlur" @focus="handleFocus" > </template> <script> export default { name: 'Input', props: { value: { type: String | Number } }, data() { return { currentValue: '' } }, watch: { value(newval) { this.currentValue = newval } }, mounted() { }, methods: { handleChange(e) { const value = e.target.value; this.$emit('input', value) this.$parent.$emit('onChangeInput', value) // 结合$on和$emit }, handleBlur() { this.$parent.$emit('onBlurInput', this.currentValue) // 失去焦点时校验 }, handleFocus() { this.$parent.$emit('onFoucsInput') // 失去焦点时校验 } } } </script> <style> </style>FormItem组件
<template> <div class="form-item"> <label v-if="label" :class="{'label-red': isRequire}">{{ label }}</label> <slot></slot> <p v-show="errTip" style="color: red">{{ errTip }}</p> </div> </template> <script> import {checkType} from '../checkType.js' export default { name: 'formItem', props: { filename: [String], // 对应哪个规则 label: [String] }, data() { return { parentRules: [], checking: '', errTip: '', currentVal: '', // 当前值 isRequire: false, // 必传 } }, created() { }, mounted() { // 获取父级元素的rules,对应自己的校验规则 // console.log(this.$parent.rules[this.filename], this.filename) this.parentRules = this.$parent.rules[this.filename] || []; this.isRequire = this.parentRules.some(rule => rule.require); this.init(); }, methods: { init() { this.$on('onChangeInput', this.handleChange) this.$on('onBlurInput', this.handleBlur) this.$on('onFoucsInput', this.onFoucsInput) // 清除错误状态 }, // 过滤带有trigger的rules数据,如果没有,则不用验证,有则需要验证 filterRules(trigger) { return this.parentRules.filter((item) => { return item.trigger && item.trigger.indexOf(trigger) > -1; }) }, // 处理过滤数据,封装校验规则 handleVaticad(trigger, callback=function(){}) { const rules = this.filterRules(trigger); if(!rules && !rules.length) { return 'error' } // 判断规则 for(let i = 0; i<rules.length; i++) { if(this.checking === 'error') { break } this.handleCheckAllType(rules[i]) } return this.checking }, // 统一的判断规则,非空,和校验 handleCheckAllType(obj) { if((obj.require && !this.currentVal) || (obj.type && !checkType.check(this.currentVal, obj.type))) { this.errTip = obj.message; this.checking = 'error'; return false; } // if(obj.type && !checkType.check(this.currentVal, obj.type)){ // this.errTip = obj.message; // this.checking = 'error'; // return false; // } this.checking = 'success'; }, handleChange(val) { // console.log({val}) }, handleBlur(val) { this.currentVal = val; this.handleVaticad('blur') }, onFoucsInput() { this.errTip = ''; this.checking = ''; } } } </script> <style scoped> .label-red { position: relative; } .label-red::after { content: '*'; color: red; position: absolute; left: -9px; top: 0; font-size: 14px; } </style> -
form组件<template> <div class="form"> <slot></slot> </div> </template> <script> export default { name: 'formx', props: { rules: [Object], // 规则数组 fieldList: [Object], // 包含的input的model值 }, created() { // 由于组件是从内到外渲染的,所以子组件渲染好之后,可在created中获取所有子组件的实例 this.arrList = this.$children }, data() { return { arrList: [] } }, methods: { // 需要有一个点击校验所有的规则,做一个回调功能的promise handleFormItemRules() { return new Promise((resolve) => { let checking = 'success'; this.arrList.forEach((item) => { item.handleVaticad('blur') if(item.checking === 'error') { checking = item.checking; } }) resolve(checking) }) } } } </script> <style> </style> -
checkType文件export const checkType = (function () { const rules = { isNumber: /^[0-9]*$/, email: /^([a-zA-Z0-9]+[-|_|.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[-|_|.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/ } return { check(str, type) { return rules[type].test(str) }, addRules(rule, type) { rules[type] = rule; } } })() -
最后效果图