vue组件

关于组件封装

vue组件系统提供一种抽象,让我们可以使用独立可复用的组件来构建大型应用,任意类型的应用界面可以抽象为一个组件树。组件化可以提高开发效率,方便重复使用,简化调试步骤,提升项目可维护性,便于多人协同开发。所以更多的大型项目中会封装一些组件来使用。
这里仿造element的form表单来写一个,更多的是学习组件封装的技巧,最重要的还是在具体项目中的刻意练习。

对于组件的功能分析,并分成多个组件

首先看这个组件的具体要实现怎么样的功能,比如element的form表单(后面直接写form表单,具体的功能也可以参照element),实现数据的收集,校验并且提交。但是将功能详细的切分:1.首先我们输入的或者通过获取来显示的数据我们要维护,这里需要一个Input的输入和数据显示的双向数据绑定的这里我们命名KInput,2.要执行校验,显示错误信息,添加label标签这里命名该组件为KformItem,3.指定数据校验规则,我们命名该组件为Kform

KInput组件的实现

<template>
    <div>
       <!-- 自定义组件双向绑定: :value  @input -->
       <!-- $attrs是将在父组件中绑定的元素并且在props中没有被生命的直接显示在子组件上 -->
       <input :type="type" :value="value" @input="onInput" v-bind="$attrs">
    </div>
</template>

<script>
    export default {
    inheritAttrs:false,  //设置为false将属性的继承关闭掉
     props:{
        value:{
        type:String,
        default:''
        },
        type:{
            type:String,
            default:'text'
        }
     } ,
     methods:{
         onInput(e){
           //派发一个input事件
           this.$emit('input',e.target.value)

           //值发生变化的时候,就是需要校验的时候
           this.$parent.$emit('validate')
        //  对于$emit来说就是谁派发,谁监听。这里可以通过父辈的派发,再由父辈监听
         }
     }  
    }
</script>

这里要实现的就是将传入的数据显示,并在页面修改数据的时候通过$emit将数据派发出去。

注意事项

这里采用了$attrs ,attrs就是将绑定在父组件上面的元素并且是没有通过props传递过来的直接显示。
同时也设置了inheritAttrs:false。将通过attrs传递的属性的继承性关闭。这个在使用的时候:

   <KForm :model='userInfo' :rules='rules' >
      <!-- 用户名 -->
      <KFormltem label='用户名'  prop="username">
        <KInput placeholder="请输入用户名" v-model="userInfo.username"></KInput>
      </KFormltem>

placeholder="请输入用户名"是没有通过props,而是$attrs传递的,如果没有设置inheritAttrs:false会出现在在父组件也有这个属性,但是当设置为false时,只会出现input组件上:
蛇者
在没有设置为false的时候:
在这里插入图片描述

KformItem组件的实现

<template>
    <div>
        <!-- label -->
        <label v-if="label">{{label}}</label>
        <!-- 容器,放插槽 -->
         <slot></slot>
         <p v-if="error" class="setcolor">{{error}}</p>
         <!-- 这里的校验信息不是传入的,而是自己的状态,所以要放在自己的data里面维护起来 -->
          <!-- <p>{{form.rules}}</p> -->
    </div>
</template>

<script>
import Schema from 'async-validator'
    export default {
        inject: ["form"],
        props:{
            label:{
                type:String,
                default:''
            }
        },
        data() {
            return {
                error: ' ',
                prop:{
                    type:String, 
                }
            }
        },
        mounted(){
            //监听校验事件
              this.$on("validate", () => {
                  this.validate();
               });
        },
        methods:{
            validate(){
                //执行校验
                //1.获取值和校验规则
                const rules = this.form.rules[this.prop]
                const value = this.form.model[this.prop]
                //2.执行校验,使用官方也是用的:使用官方也使用的async-validator
                const descriptor = {[this.prop]:rules}
                // 创建校验器
                const schema = new Schema(descriptor)
                // 执行校验
               return schema.validate({[this.prop]:value},errors=>{
                    //如果error存在,则说明校验失败
                    if(errors){
                     this.error = errors[0].message
                    }else{
                        this.error = ''
                    }
                })
            }
        }
    }
</script>

这里实现的是label的输入,并且留一个容器将KInput插入,还有就是表单校验的错误提示。

注意事项

这里的监听校验事件,在KInput里面的数据发生变化的时候就是在KformItem数据要进行监听的时候,但是,怎么来监听该事件呢,$emit时谁派发谁监听,因此在KInput中采用父组件派发的形式

Kform组件的实现

<template>
    <div>
      <!-- 容器:存放所有表单项 -->
      <!-- 存储值载体:保存大家数据和校验规则 -->
      <slot></slot>
    </div>
</template>

<script>
    export default {
     provide(){
         return{
             //这里传递的数据不是响应式的
             //这里采用的就是直接把当前组件实例传递下去
             //传递下去的对象是响应式的则还是可以响应式
             form:this
         }
     },
     props:{
         //数据模型
         model:{
             type:Object,
             required:true
         },
         rules:Object
     },
     methods:{
         validate(cb){
             //遍历肚子里面的所有FormItem,执行他们的validate方法
             //全部通过才算校验
             //tasks是校验结果的Promise组成的数据
             const tasks = this.$children.filter(item=>item.prop).map(item=>item.validate())
             console.log(this.$children)
             //统一处理所有的Promise结果
             Promise.all(tasks).then(()=>cb(true)).catch(()=>cb(false))
         
         }
     }
    }
</script>

这里的Kform只是一个容器,保存所有的表单,并且保存所有的规则和存储的数据。

注意事项

这里用到provide 隔代传值,但是传过去的数据并不是响应式的,这里采用传过去的值是组件本身,这样解决了传值不响应的问题

写在最后

关于组件开发看别人的是学习他人组件开发的技巧方法和精髓,更多的时候是自己在项目中的实践,哪些需要提取,哪些是输入,哪些是输出,哪些是组件内部的状态维护。都需要在实践中自己学习和把握(个人觉得是一种开发思维模式的转换,还是那句话“纸上得来终觉浅,绝知此事要躬行”)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值