2

Screen Shot 2020-04-29 at 12.52.59 PM.png

表单组件的核心需求

收集、校验、提交数据

分层设计

el-form,el-form-item,el-input等

职责分析

1.el-input:数据绑定到model的属性,触发校验
通过v-model双向绑定数据;通过dispatch让el-form-item来$emit事件,达到触发校验的目的。

<template>
    <div ...>
        <input ... @blur="hanldeBlur">
    </div>
</template>
<script>
    export default {
        methods: {
            ...,
            handleBlur() {
                this.dispatch('ElFormItem', 'el.form.blur', [this.value]);
            },
            ...
        }
    }
</script>

this.dispatch 来自于mixins中的emitter,作用是不断查找和判断父组件是否是ElFormItem,找到之后就在这个父组件上$emit("el.form.blur", ...),然后ElFormItem通过监听el.form.blur事件来校验。

2.el-form-item:根据校验规则做验证,控制显示错误信息
通过mounted内监听事件(el.form.blur)进行真正的校验;同时也通过dispatch把自己保存在el-form里面,方便el-form对整个表单validate。

<template>
    <div>
        <label ...></label>
        <div>
            <slot></slot>
        </div>
    <div>
<template>
<script>
    export default {
        methods: {
            validate(trigger, callback = noop) {
                // 使用第三方库async-validator做规则校验
                // 根据model,rules和prop获取el-input的值和校验规则rule
            },
            onFieldBlur() {
                this.validate('blur');
            },
            addValidateEvents() {
                this.$on('el.form.blur', this.onFieldBlur);
            }
        },
        mounted() {
            this.dispatch('ElForm', 'el.form.addField', [this]);
            
            this.addValidateEvents()
        }
    }
</script>

3.el-form:设置form的数据对象和校验规则,以及主动触发对
表单进行校验。

<script>
export default {
    provide() {
        return {
            elFormItem: this
        };
    },
    props: {
        model: Object,
        rules: Object,
        ...
    },
    method: {
        validate(callback) {
            this.fields.forEach(field => {
                field.validate('', (message, field) => {
                    ...
                });
             });
        }
    },
    created() {
        this.$on('el.form.addField', (field) => {
            if (field) {
              this.fields.push(field);
            }
        });
    }
}
</script>

意外发现

API文档中el-form-item也是可以接受rules,但是当同时指定el-form的rules和el-form-item的rules时,会优先使用el-form-item的rules。

getRules() {

    let formRules = this.form.rules;

    const selfRules = this.rules;
    
    ...

    return [].concat(selfRules || formRules || []).concat(requiredRule);

}

组件库常用的技巧

1.mixins
通过 emitter 这个 mixins,实现类似冒泡和广播

2.provide/inject
实现跨多层级的属性传递

3.发布-订阅模式
使用 emitter 中的 dispatch

4.slot插槽
组件设计肯定离不开插槽,el-form同时也使用了作用域插槽实现自定义error的显示

总结

el-form是一个很好的组件源码分析开始,代码设计思路清晰,用到都是基本api和知识点。

组件设计原则参考:https://engineering.carsguide...


xupea
124 声望39 粉丝

致力于前端技术,Scrum敏捷开发和STEAM教育