Field组件的工作流程

Field介绍

  • 对表单数据操作校验.对组件关联后可以自动对表单数据进行回写读取校验
  • 把需要验证表单数据交给Field去处理

工作流程图

在这里插入图片描述

  • 通过事件的方式,来让Field与组件之间的数据进行流动.(就好比数据的回显)

方法的分析

请先导读官网的Field,讲的很明白了,不懂的可以问题.

预备知识

  1. forceUpdate - React的方法, 当props和state不改变时,可以使用forceUpdate去强制重新渲染页面, 例子请参考

  2. 了解utils中的方法

constructor

  • 构造方法就是用来初始化变量的

  • 需用户传递组件的this- new Filed(this)

  • 还应该注意一点, 当在和Form组件一起使用时,分两种情况

    • 情况1 - 当用户在Form组件中不创建Filed时,在Form组件内部会自动创建Field组件.
    • 情况2 - 当用户在Form组件中创建Filed时,在Form组件内部会就不会自动创建Field组件,使用用户创建的Field对象.
  • 参数: constructor(com, options = {}) {}

    • 参数1: 组件的this,一般是new Field(this)
    • 参数2: 请参考(这里)[https://fusion.design/component/basic/field#demo-api]
    constructor(com, options = {}) {
        if (!com) {
            log.warning('`this` is missing in `Field`, you should use like `new Field(this)`');
        }

        this.com = com; // 代表组件对象,必须传 .例如:     field = new Field(this);    // 实例创建
        this.fieldsMeta = {};
        this.cachedBind = {};  // 缓存变量的
        this.instance = {}; // 实例

        this.values = options.values || {};

        this.options = Object.assign({
            parseName: false, //  当为true时,把 init('obj.b') 的数据转换成 obj={obj:{b:'value'}};,当为false时,  obj={"obj.b": "value"},
            forceUpdate: false, //仅建议PureComponent的组件打开此强制刷新功 https://juejin.im/post/5b614d9bf265da0fa759e84b
            scrollToFirstError: true,// ? field.validate的时候滚动到第一个出错的组件, 如果是整数会进行偏移
            first: false,//
            onChange: func.noop, // 所有组件的change都会到达这里[setValue不会触发该函数]
            autoUnmount: true,// 是否修改数据的时候就自动触发校验, 设为 false 后只能通过 validate() 来触发校验
        }, options);
        console.log(this);
        ['init',
        'getValue', //获取单个控件的值
        'getValues',// 获取控件的值, 不传的话获取所以控件的值
        'setValue', // 设置单个控件的值
        'setValues',// 设置一组输入控件的值
        'getError',//  获取单个输入控件的 Error
        'setError',// 设置单个输入控件的 Error
        'setErrors',// 设置一组输入控件的 Error
        'validate',// 校验并获取一组输入域的值与 Error
        'getState', // 判断校验状态
        'reset', //重置一组输入控件的值、清空校验
        'resetToDefault', // 重置一组输入控件的值为默认值
        'remove' // 删除某一个或者一组控件的数据,删除后与之相关的validate/value都会被清空
        ].forEach((m) => {//进行绑定
            this[m] = this[m].bind(this);
        });

        // 若用户设置values初始化,对变量进行初始化
        if (options.values) {
            this.setValues(options.values, false);
        }
    }

    // 每一个变量初始化
    setValue(name, value, reRender = true) {
        // 对field变量初始化
        if (name in this.fieldsMeta) {
            this.fieldsMeta[name].value = value;
        }
        // 对this.values初始化
        if (this.options.parseName) {
            this.values = setIn(this.values, name, value);
        } else {
            this.values[name] = value;
        }
        reRender && this._reRender();
    } 

    // 初始化代码
    setValues(fieldsValue = {}, reRender = true) {
        if (!this.options.parseName) { // 正常变量的表达式
            Object.keys(fieldsValue).forEach(name => {
                this.setValue(name, fieldsValue[name], false);
            });
        } else { // 可能含有obj.a这样的变量
            // NOTE: this is a shallow merge
            // Ex. we have two values a.b.c=1 ; a.b.d=2, and use setValues({a:{b:{c:3}}}) , then because of shallow merge a.b.d will be lost, we will get only {a:{b:{c:3}}}
            this.values = Object.assign({}, this.values, fieldsValue); 
            const fields = this.getNames();// // 获取FileMeta的变量名
            fields.forEach(name => { // 遍历所以的field的变量
                const value = getIn(this.values, name);
                if (value !== undefined) {
                    // copy over values that are in this.values
                    this.fieldsMeta[name].value = value;
                } else {
                    // if no value then copy values from fieldsMeta to keep initialized component data
                    this.values = setIn(
                        this.values,
                        name,
                        this.fieldsMeta[name].value
                    );
                }
            });
        }
        reRender && this._reRender();
    }


    //trigger rerender
    // 是否重新渲染
    _reRender() {
        if (this.com) {
            if (!this.options.forceUpdate && this.com.setState) {
                this.com.setState({});
            } else if (this.com.forceUpdate) {
                this.com.forceUpdate(); //forceUpdate 对性能有较大的影响,成指数上升
            }
        }
    }


init

  • 初始化每一个组件
  • 参数
    • 参数1 - 每个组件的唯一标示
    • 参数2 - 请参考本文的constructor或官网
    • 参数3 - 组件自定义的事件可以写在这里(Object形势)

    /**
     * Controlled Component
     * @param {String} name
     * @param {Object} fieldOption
     * @returns {Object} {value, onChange}
     */
    init(name, fieldOption = {}, rprops) {
        const {
            initValue, // 初始值
            valueName = 'value',// 组件值的属性名称,如 Checkbox 的是 checked,Input是 value	
            trigger = 'onChange',// // 触发数据变化的事件名称
            rules = [], // 校验规则
            props = {},//  // 组件自定义的事件可以写在这里
            getValueFromEvent = null, //自定义从onChange事件中获取value的方式,一般不需要设置. 详细用法查看demo 自定义数据获取
            autoValidate = true, // 是否修改数据的时候自动触发校验单个组件的校验, 设为 false 后只能通过 validate() 来触发校验	
        } = fieldOption;

        // add code 
        // parseName为true时,把 init('obj.b') 的数据转换成 obj={obj:{b:'value'}};
        const { parseName } = this.options;


        // 把自定义event和组件props放在一起
        const originalProps = Object.assign({}, props, rprops);

        // 设置默认值
        const defaultValueName = `default${valueName[0].toUpperCase()}${valueName.slice(
            1
        )}`;//defaultValueName = 'defaultValue';
        
        // field初始化
        const field = this._getInitMeta(name);
        console.log(field);
        // 默认值初始值的设置
        let defaultValue;

        // 默认值判断的改变
        // if (typeof initValue !== 'undefined') { // 初始值不是undefined时,进行初始化
        //     defaultValue = initValue;
        // } else if (originalProps[defaultValueName]) { //当用户传递defaultValue属性时 defaultValue  <Input defaultValue="this is default value" />
        //     defaultValue = originalProps[defaultValueName];
        // } else {
        //     defaultValue = getIn(this.initValues, name);
        // }
        if(typeof initValue !== 'undefined') {// 若options传递initValue,则设置为默认值
            defaultValue = initValue;
        }else if(typeof originalProps[defaultValueName]) {
            defaultValue = originalProps[defaultValueName];
        }

        

        // file变量的定义
        Object.assign(field, {
            valueName, // 组件值的属性名称,如 Checkbox 的是 checked,Input是 value	
            initValue: defaultValue, // 每一个控件的初始化值
            disabled: // 是否被禁用
                'disabled' in originalProps ? originalProps.disabled : false,
            getValueFromEvent, // 是否有自定义event
            rules: Array.isArray(rules) ? rules : [rules], // 规则的定义 , 转换为数组
            ref: originalProps.ref, // 保存ref
        });
 
        // Controlled Component, should alwasy equal props.value
        if (valueName in originalProps) {
            field.value = originalProps[valueName]; // 把当前组件的属性名,复制给value Input是value, checkbox为checked ,把当前组件的值,复制给value
            // value 就可以保存 当前组件的值了. Input保存originalProps['value'], checkbox保存值为Input保存originalProps['checked']
             
            if (parseName) {
                // 把 init('obj.b') 的数据转换成 obj={obj:{b:'value'}};
                //  并把Field中options定义的values放在一起
                this.values = setIn(this.values, name, field.value);
            }else { // 若为false直接挂在到Field对象上的values上
                this.values[name] = field.value;
            }

        }
        
        // 若用户没有传参数, 设置默认值
        if (!('value' in field)) {
            if(parseName) {
                // 查找this.values是否存在name属性
                const cachedValue = getIn(this.values, name);
                field.value = 
                    typeof cachedValue !== 'undefined'
                        ? cachedValue 
                        : defaultValue;
            } else {// 当传的值不是obj.c的形式时
                const cachedValue = this.values[name];
                field.value = typeof cachedValue !== 'undefined'
                    ? cachedValue 
                    : defaultValue;
            }
            // 之前的方式, 问题 会出现当obc.a形式的时候,会出现问题
            // field.value = defaultValue;
        }

        // 当parse为true时, 初始值没有含有对应的值
        if(parseName && !getIn(this.values, name)) {
            this.values = setIn(this.values, name, field.value);
        } else if(!parseName && !this.values[name]) {
            this.values[name] = field.value;
        }
  
        // console.log(this);
        // Component props
        const inputProps = {
            'data-meta': 'Field', // 标识
            id: name, // name
            ref: this._getCacheBind(name, `${name}__ref`, this._saveRef), // 绑定控件,存在到cache
            [valueName]: field.value, // 存在对应组件的值
        };

        let rulesMap = {};

        // 验证
        if (this.options.autoValidate && autoValidate !== false) {
            // trigger map
            rulesMap = mapValidateRules(field.rules, trigger);

            // validate hook
            for (const action in rulesMap) {
                if (action === trigger) {
                    continue;
                }

                const actionRule = rulesMap[action];
                inputProps[action] = (...args) => {
                    this._validate(name, actionRule, action);
                    this._callPropsEvent(action, originalProps, ...args);
                    this._reRender();
                };
            }
        }

        // onChange hack
        inputProps[trigger] = (...args) => {
            this._callOnChange(name, rulesMap[trigger], trigger, ...args);
            this._callPropsEvent(trigger, originalProps, ...args);
            this.options.onChange(name, field.value);
            this._reRender();
        };

        delete originalProps[defaultValueName];

        return Object.assign({}, originalProps, inputProps);
    }


getValues

  • 获取定义的属性的值
  • 使用方式
    • this.field.values();
    • this.field.values([‘变量名’]);


```js
    //获取单个属性值
    getValue(name) {
        
        if (this.options.parseName) {
            return getIn(this.values, name);
        }
        
        return this.values[name];
    }

    /**
     * 1. get values by names.
     * 2. If no names passed, return shallow copy of `field.values`
     * @param {Array} names
     */
    getValues(names) {
        const allValues = {};

        if (names && names.length) {
           
            names.forEach(name => {
                allValues[name] = this.getValue(name);
            });     
        } else {
            Object.assign(allValues, this.values);
        }

        return allValues;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值