vue表单验证你真的会了吗?vue表单验证(form)validate

前言

很久没有写文章了,学习了一下webpack,基础的一些组件,今天带来form表单验证组件(element.iviewui)的一期教程(作为一个菜鸡毕竟经历众多项目可以给一些新手一点提示 (QQ群技术讨论)838293023备注(github进来的

github 技术文档 技术文档会持续更新

效果图

 

1.原理解释

考虑

我们看一下我们可以用form去整体触发校验也可以单个input来触发form-item 进行校验 童鞋们现在可能感觉还是没懂,没关系继续往下看。

2.派发和广播

为什么要用广播和派发呢。通常我们和业务没有关系的组件尽量不要使用vuex和bus(事件总线)。 下面我送上广播和派发的代码。我们在需要调用组件绑上 this.$on('event',res=>()) ,通过派发和广播进行调用 $emit 。

  • 派发是向上查找且只调用1个
  • 广播是向下查找调用多个
  • 注意⚠️所有的组件都要写上name
  • 通过混合器 mixins 来使用

emitter.js

/**

* 递归使用 call 方式this指向

* @param componentName // 需要找的组件的名称

* @param eventName // 事件名称

* @param params // 需要传递的参数

*/

function broadcast(componentName, eventName, params) {

// 循环子节点找到名称一样的子节点 否则 递归 当前子节点

this.$children.map(child=>{

if (componentName===child.$options.name) {

child.$emit.apply(child,[eventName].concat(params))

}else {

broadcast.apply(child,[componentName,eventName].concat(params))

}

})

}

export default {

methods: {

/**

* 派发 (向上查找) (一个)

* @param componentName // 需要找的组件的名称

* @param eventName // 事件名称

* @param params // 需要传递的参数

*/

dispatch(componentName, eventName, params) {

let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点

let name = parent.$options.name; // 获取当前组件实例的name

// 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点

// 循环出当前名称的一样的组件实例

while (parent && (!name||name!==componentName)) {

parent = parent.$parent;

if (parent) {

name = parent.$options.name;

}

}

// 有节点表示当前找到了name一样的实例

if (parent) {

parent.$emit.apply(parent,[eventName].concat(params))

}

},

/**

* 广播 (向下查找) (广播多个)

* @param componentName // 需要找的组件的名称

* @param eventName // 事件名称

* @param params // 需要传递的参数

*/

broadcast(componentName, eventName, params) {

broadcast.call(this,componentName, eventName, params)

}

}

}

3.async-validator

不懂 async-validator 可以去官网看看 github

yarn add async-validator // 因为当前这个插件是需要打包到项目里的所以不能加-D

4.api设计

我们看一下下面 element 官网的图`

form 有2个注入的字段 :rules 规则,和 :model 当前form的值会通过 model 的值和 rules 进行匹配来进行校验.

form-item 有2个注入的字段 lable 和 prop ( prop )是来和 form 进行匹配来获取当前的 form-item 的值的

input 其实有当前的 @input 的方法。 v-model 就不解释了

 

form

我们在 form 先开始注入当前所有的 form-item 实例(获取)

created 会在生命周期开始的时候绑定和删除当前实例的方法。通常绑定都在页面dom开始前调用需要在 dom 加载完

provide 配合inject 使用让子组件可以调用当前父组件的方法以及data

下面都写了备注可以放心食用(经过测试当前是可以进行校验的)

form.vue

<template>

<form>

<slot></slot>

</form>

</template>

<script>

export default {

name: "aiForm",

provide(){ // [不懂的可以看看](https://cn.vuejs.org/v2/api/#provide-inject)

return {

form: this

}

},

props: {

// 当前 form 的model

model: {

type: Object

},

// 验证

rules: {

type: Object

}

},

data(){

return{

fields: [] // 储存当前的 form-item的实例

}

},

created(){

// 存当前实例

let that =this;

this.$on('on-form-item-add',item=>{

if (item) {

that.fields.push(item)

}

});

// 删除当前有的实例

this.$on('on-form-item-remove',item=>{

if (item.prop) {// 如果当前没有prop的话表示当前不要进行删除(因为没有注入)

that.fields.splice(that.fields.indexOf(item),1)

}

})

},

methods:{

/**

* 清空

*/

resetFields(){//添加resetFields方法使用的时候调用即可

/**

* 当前所有当form-item 进行赋值

*/

this.fields.forEach(field => {

field.resetField();

});

},

/**

* 校验 公开方法:全部校验数据,支持 Promise

*/

validate(callback){

return new Promise(resolve=>{

/**

* 当前所有当form-item 进行校验

*/

let valid = true; // 默认是通过

let count = 0; // 来匹配当前是否是全部检查完

this.fields.forEach(field => {

// 每个实例都会有 validation 的校验的方法

field.validation('',error=>{

// 只要有一个不符合那么当前的校验就是未通过的

if (error) {

valid = false;

}

// 通过当前检查完所有的form-item的时候才会调用

if (++count === this.fields.length) {

resolve(valid);// 方法使用then

if (typeof callback === 'function') {

callback(valid);// 直接调用注入的回调方法

}

}

});

});

})

}

}

}

</script>

5.form-item

  •  form-item比较复杂我们一个一个讲
  • isRequired来判断当前是否需要必填
  • validateState来判断当前校验的状态
  • validateMessage当前的错误的值
  • inject: ['form'] 我们就可以通过this.from.xxx来调用父组件的事件以及值了
  • computed下的fieldValue可能在不停的变化所以我们通过计算属性来使用
  • initialValue 默认的值我们在mounted的时候且当前需要进行校验的时候(prop有的时候)会赋值
  • mixins: [Emitter]混合器就是里面的方法以及date都可以在当前调用使用频繁的都可以放在混合器里面
  • 我们form-item 会传入input的两个方法blur和change(input原生使用的@input)通过form传入的校验rules里面的trigger来判断

form-item.vue

<template>

<div>

<label :class="isRequired?'ai-form-item-label-required':''">{{label}}</label>

<div>

<slot></slot>

<div class="ai-form-item-message" v-if="validateState==='error'">{{validateMessage}}</div>

</div>

</div>

</template>

<script>

import Emitter from '../../mixins/emitter';

import schema from 'async-validator';

export default {

name: "aiFormItem",

mixins: [Emitter],

inject: ['form'],

props: {

label: {

type: String,

default: ''

},

prop:{

type: String

},

},

computed:{

fieldValue () {

return this.form.model[this.prop];

},

},

data(){

return {

initialValue: '', // 储存默认值

isRequired: false, // 当前的是否有问题

validateState: '', // 是否校验成功

validateMessage: '', // 校验失败文案

}

},

methods:{

/**

* 绑定事件 进行是否 required 校验

*/

setRules(){

let that = this;

let rules = this.getRules();//拿到父组件过滤后当前需要使用的规则

if (rules.length) {

// every 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)

// some 只要有一个符合就返回true

this.isRequired = rules.some(rule=>{

// 如果当前校验规则中有必填项,则标记出来

return rule.required;

})

}

/**

* blur 事件

*/

this.$on('on-form-blur',that.onFieldBlur);

/**

* change 事件

*/

this.$on('on-form-change',that.onFieldChange)

},

/**

* 从 Form 的 rules 属性中,获取当前 FormItem 的校验规则

*/

getRules () {

let that = this;

let rules = that.form.rules;

rules = rules?rules[that.prop]:[];

return [].concat(rules||[])//这种写法可以让规则肯定是一个数组的形式

},

/**

* Blur 进行表单验证

*/

onFieldBlur(){

this.validation('blur')

},

/**

* change 进行表单验证

*/

onFieldChange(){

this.validation('change')

},

/**

* 只支持 blur 和 change,所以过滤出符合要求的 rule 规则

*/

getFilteredRule (trigger) {

let rules = this.getRules();

// !res.trigger 没有调用方式的时候默认就校验的

// filter 过滤出当前需要的规则

return rules.filter(res=>!res.trigger || res.trigger.indexOf(trigger)!==-1)

},

/**

* 校验数据

* @param trigger 校验类型

* @param callback 回调函数

*/

validation(trigger,callback=function () {}){

// blur 和 change 是否有当前方式的规则

let rules = this.getFilteredRule(trigger);

// 判断当前是否有规则

if (!rules || rules.length === 0) {

return

}

// 设置状态为校验中

// async-validator的使用形式

this.validateState = 'validating';

var validator = new schema({[this.prop]: rules});

// firstFields: true 只会校验一个

validator.validate({[this.prop]: this.fieldValue}, { firstFields: true },(errors, fields) => {

this.validateState = !errors ? 'success' : 'error';

this.validateMessage = errors ? errors[0].message : '';

callback(this.validateMessage);

});

},

/**

* 清空当前的 form-item

*/

resetField(){

this.form.model[this.prop] = this.initialValue;

}

},

// 组件渲染时,将实例缓存在 Form 中

mounted(){

// 如果没有传入 prop,则无需校验,也就无需缓存

if (this.prop) {

this.dispatch('aiForm','on-form-item-add', this);

// 设置初始值,以便在重置时恢复默认值

this.initialValue = this.fieldValue;

// 添加表单校验

this.setRules()

}

},

// 组件销毁前,将实例从 Form 的缓存中移除

beforeDestroy(){

this.dispatch('iForm', 'on-form-item-remove', this);

},

}

</script>

<style scoped>

<!--当前css-->

.ai-form-item-label-required:before{

content: '*';

color: red;

}

.ai-form-item-message {

color: red;

}

</style>

5.input

  •  value 支持一个入参
  • 因为当前是一个 input 注入的参数是不能直接放到 input 里面使用的所以先赋值给了 defaultValue 然后用 watch 来不停给 defaultValue 赋值达到一个父组件修改后的一个绑定

<template>

<input type="text"

@input="handleInput" // change

@blur="handleBlur"

:value="defaultValue"

>

</template>

<script>

import Emitter from '../../mixins/emitter.js'

export default {

name: "aiInput",

mixins: [Emitter],

props: {

value: {

type: String,

default: ''

}

},

data(){

return {

defaultValue: this.value

}

},

watch:{

value (val) {

this.defaultValue = val;

}

},

methods:{

/**

* change 事件

* @param event

*/

handleInput(event){

// 当前model 赋值

this.defaultValue = event.target.value;

// vue 原生的方法 return 出去

this.$emit('input',event.target.value);

// 将当前的值发送到 aiFormItem 进行校验

this.dispatch('aiFormItem','on-form-change',event.target.value)

},

/**

* blur 事件

* @param event

*/

handleBlur(event){

// vue 原生的方法 return 出去

this.$emit('blur',event.target.value);

// 将当前的值发送到 aiFormItem 进行校验

this.dispatch('aiFormItem','on-form-blur',event.target.value)

}

}

}

</script>

最后

最后给上一个当前可以的使用方式

<template>

<div class="home">

<button @click="changeButton">测试</button>

<ai-form ref="formItems" :model="formValidate" :rules="ruleValidate">

<ai-form-item label="用户名" prop="name">

<ai-input v-model="formValidate.name"/>

</ai-form-item>

</ai-form>

</div>

</template>

<script>

import AiForm from "../components/form/form";

import AiFormItem from "../components/form/form-item";

import AiInput from "../components/input/ai-input";

export default {

name: 'home',

components: {AiInput, AiFormItem, AiForm},],

data(){

return{

formValidate: {

name: '123z',

mail: ''

},

ruleValidate: {

name: [

{ required: true, message: '用户名不能为空', trigger: 'blur' },

],

}

}

},

methods:{

changeButton(){

this.$refs.formItems.resetFields() // 清空方法

this.$refs.formItems.validate() // 验证方法

.then(res=>{

console.log(res)

})

}

},

}

</script>

小结

可能现在小伙伴还是不懂。。俗话说;师傅领进门,修行在个人。代码上的备注写的也够多了。

以上是 vue表单验证你真的会了吗?vue表单验证(form)validate 的全部内容, 来源链接: utcz.com/z/318655.html

回到顶部