form组件,实现过程

Form:管理数据模型-model,校验规则-rules,全局校验方法validate

FormItem:显示标签-label,执行校验-prop,显示校验结果

Input:绑定数据模型 v-model,通知FormItem执行校验

 

1、实现自定义的双向绑定

// KInput.vue中

<div>
    <!-- 自定义组件要实现v-model,必须实现 :value,@input -->
   <!-- $attr存储的是props之外的部分,放在此处后,就可以不需要设置type了 --> <input v-bind="$arrt" :value="value" @input="onInput"> </div>

inheritAttrs: false, // 避免顶层容器继承属性 methods: { onInput(e){ // 通知父组件数值变化 this.$emit('input', e.target.value) } }

 

form文件夹下的index.vue组件

<div>
    <KInput v-model="model.username"></KInput>
    <KInput v-model="model.password" type="password"></KInput>
    {{model}}
</div>

import KInput from './KInput.vue'
data () {
    return {
        model: {
            username: 'tom',
            password: ''
        }
    }
},
components: {
    KInput
}

 

v-model相当于一个语法糖

<KInput v-model="model.username"></KInput>

等同于

<KInput :value="model.username" @input="xxxx"></KInput>

 

 

FormItem

任务1:给Input预留插槽 - slot

任务2:能够展示label 和 校验信息

任务3:能够进行校验

 

 

index.vue 文件

<div>
    <KForm :model="model" :rules="rules" ref="loginForm">
        <KFormItem label="用户名" prop="username">
            <KInput v-model="model.username"></KInput>
        </KFormItem>
        <KFormItem label="密码" prop="password">
            <KInput v-model="model.password" type="password"></KInput>
        </KFormItem>
        <KFormItem>
            <button @click="onLogin">登录</button>
        </KFormItem>
    </KForm>
    {{model}}
</div>

import KInput from './KInput.vue'
import KFormItem from './KFormItem.vue'
import KForm from './KForm.vue'
export default {
    data () {
        return {
            model: {
                username: 'tom',
                password: ''
            },
            rules: {
                username: [{required: true, message: '用户名必填'}],
                password: [{required: true, message: '密码必填'}]
            }
        }
    },
    components: {
        KInput,
        KFormItem,
        KForm
    },
    methods: {
        onLogin() {
            this.$refs.loginForm.validate((isValied) => {
                if(isValied){
                    alert("登录!!")
                }else{
                    alert("有错!!")
                }
            })
        }
    }
}

 

 

KForm.vue  文件

<div>
    <slot></slot>
</div>


export default {
    provide(){
        return{
            form: this // 传递Form实例给后代
        }
    },
    props:{
        model: {
            type: Object,
            required: true
        },
        rules: {
            type: Object
        }
    },
    data () {
        return {

        }
    },
    methods: {
        validate(callback){
            // map的结果是若干Promise数组
            const tasks = this.$children
                .filter(item => item.prop)
                .map(item => item.validate())
            // 所有任务必须全部成功才算校验通过
            Promise.all(tasks)
                .then(() => callback(true))
                .catch(() => callback(false))
        }
    }
}

 

KFormItem.vue   文件

<div>
    <label v-if="label">
        {{label}}
    </label>
    <!-- 存放input -->
    <slot></slot>
    <!-- 校验信息 -->
    <p v-if="errorMessage">
        {{errorMessage}}
    </p>
</div>


import Schema from 'async-validator'
export default {
    inject: ['form'],
    props: {
        label: {
            type: String,
            default: ''
        },
        prop: String
    },
    data () {
        return {
            errorMessage: ''
        }
    },
    mounted () {
        // 监听校验事件,并执行监听
        this.$on('validate', () => {
            this.validate()
        })
    },
    methods: {
        validate(){
            // 执行组件校验
            // 1、获取校验规则
            const rules = this.form.rules[this.prop]

            // 2、获取数据
            const value = this.form.model[this.prop]

            // 3、执行校验
            // 使用async-validator库(element-ui也使用的这个校验库)
            // npm i async-validator -S
            const desc = {
                [this.prop]: rules
            }
            const schema = new Schema(desc)
            // 参数1是值, 参数2是校验错误对象数组
            // 返回的Promise  boolean
            return schema.validate({[this.prop]: value}, errors => {
                if(errors){
                    // 有错
                    this.errorMessage = errors[0].message
                }else{
                    // 如果没错,就清除错误信息
                    this.errorMessage = ''
                }
            })

        }   
    }
}

 

KInput.vue  文件

<div>
    <!-- 自定义组件要实现v-model,必须实现 :value,@input -->
    <!-- $attrs存储的是props之外的部分 -->
    <!-- {type: 'password'} -- v-bind="$attrs"相当于将其展开 -->
    <input :value="value" @input="onInput" v-bind="$attrs">
</div>

export default {
    inheritAttrs: false,
    props:{
        value: {
            type: String,
            defaule: ''
        }
    },
    data () {
        return {
            
        }
    },
    components: {

    },
    created () {
    },
    methods: {
        onInput(e){
            // 通知父组件数值变化
            this.$emit('input', e.target.value)

            // 通知FormItem校验
            this.$parent.$emit('validate')
        }
    }
}

 

转载于:https://www.cnblogs.com/haishen/p/11278033.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值