• ant design form Rc-Form源码逐行分析


    Rc-Form源码分析

    作者:姚观寿,高级前端工程师,天虹数字灵智科技

    前段时间因为公司需要做比较复杂的表单校验,多层嵌套和动态form组件创建,为了能够写出更好的form表单组件我特意去看了下他底层源码, Rc-Form其实就是阿里ant design form的底层源码,今天我们来学习下Rc-Form源码分析,学习完以后我们在使用ant design form 会更加游刃有余。

     

    Rc-Form功能: 主要是用来 创建和收集字段的数据和校验字段错误信息,让开发程序员少代码能实现这个的功能。

      

    • 接下来我们来一起看看Rc-Form整个代码构思,Rc-Form 主要分为几个模块 createBaseForm 的 getForm 向整个组件props注入 setFieldsValue, getFieldsValue,resetFields,validateFields ,getFieldDecorator, getFieldProps。

    • createFieldsStore 是用来存储字段fields value 和 error 和 方法。里面用到了 订阅和发布模式。类似于redux的一个东西,主要核心方法:setFields,resetFields,getFieldValuePropValue, clearField,getFieldsError。

    • 代码和程序流程图思维导图

    • 如果你觉得不错,请帮我在git仓库上点赞,谢谢了,你的支持是我开源的动力。
    • git逐行分析源码地址 : https://github.com/qq281113270/antd-rcfom.git  
    • Rc-Form 源码基本构思: http://naotu.baidu.com/file/5548c203caa4d01bccc80660deec923d?token=42d2b5b01a256c28

      Rc-Form 源码详细分析:http://naotu.baidu.com/file/bb9abeca5d9a6878c6a27202dd9378dd?token=9768523373fe9934

    • Rc-Form文件分析

       

      接下来我们细说整个代码。

       

      首先我们需要把这个code下载下来。第一步安装node_modules

       

      npm i --save rc-form

       

      这样就可以把rc-form源码下载下来了,

       

      然后我们最好启动一个react项目,当然我们可以使用react-create-app创建一个react项目。

       

      然后把rc-form源码包源码最好拷贝到react项目中的src 目录中,这样后期我们在rc-form组件中写上注释,还可以保留。

       

      下载下来之后_rc-form@2.4.11@rc-form 包会有几个文件夹目录。一般webpack 默认引用的的是es包。

       

       

       outputpath
      ├── dist # umd module
          UMD(Universal Module Definition)是 AMD 和 CommonJS 的糅合,跨平台的解决方案
          UMD 打包出来的文件可以直接通过 script 插件 html 中使用
      ;(function(root, factory) {
      if (typeof exports === 'object' && typeof module === 'object')
        module.exports = factory()
      else if (typeof define === 'function' && define.amd) define([], factory)
      else if (typeof exports === 'object') exports['A'] = factory()
      else root['A'] = factory()
      })(window, function() {
      //...
      })
         
      ├── es   # es module
      ES Module 不是对象,是使用 export 显示指定输出,再通过 import 输入。此法为编译时加载,编译时遇到 import 就会生成一个只读引用。等到运行时就会根据此引用去被加载的模块取值。所以不会加载模块所有方法,仅取所需。
      export const m = 1
      export {
      m
      }


      ├── lib   # commonjs module
        CommonJS 模块是对象,是运行时加载,运行时才把模块挂载在 exports 之上(加载整个模块的所有),加载模块其实就是查找对象属性。
      导出使用 module.exports,也可以 exports。就是在此对象上挂属性。exports 指向 module.exports,即 exports= module.exports
       
      加载模块通过 require 关键字引用
      module.exports.add = function add() {
      return
      }
      exports.sub = function sub() {
      return
      }

      const a = require('a.js')

      如果你喜欢 当然 也可以直接看 cdn 包。

       

    • 接下来我们来看文件

      createBaseForm.js

      这个js主要用于创造基本的 form 组件

      他的实现主要利用了react 的 hoc 高级组件方式实现,原理其实就是返回一个匿名函数然后在函数中传递一个子组件进来,然后利用 hoc 高阶组件 把props的form 注入进来给children组件,实现例子,这里用到以前的一些知识点 比如闭包,函数式编程,函数式柯里化。所以下面我们来简单的实现一个props.form 注入 子组件中

       // 因为第一层需要传递参数
      const createForm = (options) => {
      return (Component) => {
        return class Form extends React.Component {
          getForm() {
            return {
              getFieldsValue: () => {}, // 获取字段值得函数
              getFieldValue: () => {}, // 获取单个值得函数
              getFieldInstance: () => {}, // 获取字段实例
              setFieldsValue: () => {}, // 设置字段值
              setFields: () => {}, // 设置字段 新的值
              setFieldsInitialValue: () => {}, // 设置初始化值的函数
              getFieldDecorator: () => {}, // 用于和表单进行双向绑定,详见下方描述 装饰组件,促进双向绑定的修饰器
              getFieldProps: () => {}, // 创建待验证的表单 设置字段元数据,返回 计算被修饰组件的属性
              getFieldsError: () => {}, //获取一组输入控件的 Error ,如不传入参数,则获取全部组件的 Error
              getFieldError: () => {}, //获取某个输入控件的 Error
              isFieldValidating: () => {}, //判断一个输入控件是否在校验状态
              isFieldsValidating: () => {}, // 判断字段是否在校验中
              isFieldsTouched: () => {}, //判断是否任一输入控件经历过 getFieldDecorator 的值收集时机 options.trigger
              isFieldTouched: () => {}, //判断一个输入控件是否经历过 getFieldDecorator 的值收集时机 options.trigger
              isSubmitting: () => {}, // 是否在 提交状态
              submit: () => {}, // 表单提交函数
              validateFields: () => {}, //验证字段,返回promise
              resetFields: () => {}, // 重置字段
            };
          }
          render() {
            const props = {
              form: this.getForm.call(this),
            };
            return <Component {...props} />;
          }
        };
      };
      };

      class BaseForm extends React.Component {
      constructor(props) {
        super(props);
      }

      componentDidMount() {
        console.log(this.props);
        debugger;
      }
      render() {
        return (
          <form>
            <input />
            <select>
              <option>1</option>
            </select>
          </form>
        );
      }
      }

      const Form = createForm({ name: "abc" })(BaseForm);

      ReactDOM.render(<Form />, document.getElementById("example"));

      连接createFieldsStore类的各种方法

      • props的form上的方法大多数是调用createFieldsStore类的方法,通过调用createFieldsStore 的各种方法实现控制字段的增删改查。

      createFieldsStore.js

      • createFieldsStore 可以理解是用于存储字段信息值,包括字段值和校验,错误信息 还有 事件等。可以理解成仓库比如像redux这种。然后这个类会有各种方法包括增删改查字段,校验字段等。

        • 数据格式:

          • 每创建一个form 表单( 比如 createForm()(RcForm) ) 就会实例化createFieldsStore 一次,同时该createFieldsStore 就会产生一个实例属性fields和一个实例属性fieldsMeta

          • fields 是validateFields 调用回调函数之后,传递给用户的field值,用来记录用户输入值的对象。 数据格式为字段名称作为key, 里面 是对象value值 :

             {
            fieldName:{
              value: "1"
            }
            }
      • fieldsMeta数据 ,该数据作用是为RcForm存储操作记录使用的, 数据格式为字段名称作为key代表的是哪个字段的,然后后面是对象,对象里面存放着字段的事件,校验,初始化值,属性等      

        • fieldsMeta 新增,获取和删除方法

          • getFieldMeta // 获取单个字段的getFieldMeta 对象,如果没有则为 新增 一个空对象

          • setFieldMeta // 设置 fieldsMeta 字段信息

          • clearField // 清除Field和Meta字段

        • fields的设置和删除字段和获取值方法,

          • setFields // 设置字段 新的值

          • clearField // 清除Field和Meta字段

          • resetFields // 重置value

          • getValueFromFields // 获取字段的value值

          • getFieldValuePropValue // 获取字段的value 值

          • getFieldsValue // 获取字段的值

          • getAllValues // 获取全部字段的值

          • getAllFieldsName //获取全部字段名称

          • getFieldsError // 获取字段错误信息

          

    createFormField.js

    • 该类是为每一个字段创建一个对象用来存储该字段的数据

    • 其实该类初始化并没有做什么,可以用一个单列模式去写就可以了。

       

    创建Form程序流程

    • 一开始会调用 createBaseForm,进行 初始化 form表单一些参数比如

    createBaseForm(options)(Component) 
    //options 为整个表单配置的参数
    // Component 表单组件 为改组件注入props.form


    createBaseForm 组件的 getInitialState
    创建 初始化 fieldsStore

     

    getFieldDecorator

    • // 用于和表单进行双向绑定,详见下方描述 装饰组件,促进双向绑定的修饰器

    • 实际上他主要也是调用getFieldProps 方法,

    • 通过闭包,hoc高阶组建,利用React.cloneElement 隐形 把 props 的value和onChange注入 到组建中

    • 以下片段代码

        // 用于和表单进行双向绑定,详见下方描述 装饰组件,促进双向绑定的修饰器
        getFieldDecorator: function getFieldDecorator(
          name, // 字段名称
          fieldOption // 字段设置参数
        ) {
          var _this2 = this;
          // 创建待验证的表单 设置字段元数据,返回 计算被修饰组件的属性
          var props = this.getFieldProps(name, fieldOption);
          return function (
            fieldElem // 组件 也可以理解为react 的 vnode 虚拟dom
          ) {
          // .....
          return React.cloneElement(
              fieldElem, //原来的vnode
              // props 属性
              _extends(
                {},
                props, // 用户传进来的 props 属性
                // 获取value 属性值
                _this2.fieldsStore.getFieldValuePropValue(fieldMeta)
              )
            );
           
          .....
           

     

    getFieldProps

    • 该方法主要是返回 onChange 方法和 value 让组件变成受控组件,促进双向绑定的修饰器。

    • 调用trigger (onCollectValidate)和validateTriggers方法(onCollect)

    • 为Meta 类添加一个 MetaFiel 对象

    •  

     // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
    //
    var fieldMeta = this.fieldsStore.getFieldMeta(name);
        //获取字段选项参数
          var fieldOption = _extends(
            {
              name: name, // 字段名称
              trigger: DEFAULT_TRIGGER, //onChange 收集子节点的值的时机
              valuePropName: "value", // 字段value
              validate: [], // 验证 空数组
            },
            usersFieldOption // 字段选项参数
          );
            /// ... 省略代码
           
            return inputProps;

     

    normalizeValidateRules 获取字段验证规则

    /*
    获取收集字段验证规则,并添加到队列中
    */
    function normalizeValidateRules(
      validate, // 收集验证规则字段存储
      rules, // 字段验证规则
      validateTrigger // 触发字段验证规则事件数组
      ) {

    var validateRules = validate.map(function (item) {
      var newItem = _extends({}, item, {
        trigger: item.trigger || [],
      });
      if (typeof newItem.trigger === "string") {
        newItem.trigger = [newItem.trigger];
      }
      return newItem;
    });
    console.log("validateRules=", validateRules);
    // 如果该字段有验证规则泽添加到validateRules队列中
    if (rules) {
      validateRules.push({
        trigger: validateTrigger ? [].concat(validateTrigger) : [],
        rules: rules,
      });
    }
    console.log("validateTrigger=", validateTrigger);
    console.log("validateRules=", validateRules);
    return validateRules;
    }

     

    getValidateTriggers

    • 从normalizeValidateRules 中获取到的validateRules过滤成一个数组只要item.trigger属性该属性一般为onChange事件。

    • 通过获取到的trigger和validateTriggers来判断然后调用getCacheBind去给form表单组件绑定onChange事件和校验器。

    • 如果trigger && validateTriggers.indexOf(trigger) === -1 则表示当前form表单 并没有rules校验器。然后调用getCacheBind绑定onCollectCommon 函数 dom从原生获取值。 并且返回value值,name,fieldMeta。

    • 而trigger && validateTriggers.indexOf(trigger) !== -1 则表示当前form表单 有rules校验器。 的情况下onCollectValidate dom从原生获取值。 并且返回value值,name,fieldMeta,并且校验字段。

    function getValidateTriggers(validateRules) {
    return validateRules
      .filter(function (item) {
        //过滤数据
        return !!item.rules && item.rules.length;
      })
      .map(function (item) {
        //只要获取trigger 一般为change
        return item.trigger;
      })
      .reduce(function (pre, curr) {
        // 连接数组
        return pre.concat(curr);
      }, []);
    }

    getCacheBind 绑定onChange事件,并且返回事件对象

          // 组件事件绑定等 这里一般指的是收集onChange事件,然后返回事件对象
        getCacheBind: function getCacheBind(name, action, fn) {
          // 判断有没有绑定缓存,如果没有则先给一个空的对象
          if (!this.cachedBind[name]) {
            this.cachedBind[name] = {};
          }
          // 获取缓存
          var cache = this.cachedBind[name];
          //如果获取不到缓存那么就设置缓存
          if (!cache[action] || cache[action].oriFn !== fn) {
            cache[action] = {
              // 事件固定传参
              fn: fn.bind(this, name, action),
              oriFn: fn,
            };
          }
          //返回缓存中的fn函数
          return cache[action].fn;
        },

     

    onCollectValidate 收集验证 onchange 事件

    • 调用onCollectCommon 方法去调用onChange事件

    • 调用validateFieldsInternal 做校验并且调用 setFields 设置字段值

      // 收集验证 onchange 事件
        onCollectValidate: function onCollectValidate(name_, action) {
          console.log("arguments=", arguments);
          console.log("onCollectValidate===========");
          for (
            var _len2 = arguments.length,
              args = Array(_len2 > 2 ? _len2 - 2 : 0),
              _key2 = 2;
            _key2 < _len2;
            _key2++
          ) {
            // 收集大于2个参数组成数组存放在args数组中
            args[_key2 - 2] = arguments[_key2];
          }
          // 收集设置字段 从事件中获取值 和从事件中设置值
          var _onCollectCommon2 = this.onCollectCommon(name_, action, args),
            // 获取字段
            field = _onCollectCommon2.field,
            // 获取字段存储的对象
            fieldMeta = _onCollectCommon2.fieldMeta;
          // 新的字段
          var newField = _extends({}, field, {
            dirty: true, //检查校验字段 标志dirty 为true
          });
          // 检查校验字段 标志dirty 为true
          this.fieldsStore.setFieldsAsDirty();
          //内部验证字段
          this.validateFieldsInternal([newField], {
            action: action,
            options: {
              firstFields: !!fieldMeta.validateFirst, //当某一规则校验不通过时,是否停止剩下的规则的校验
            },
          });
        },

    onCollectCommon 收集 事件中获取值

    • onCollectCommon 收集 事件中获取值 ,调用onChange事件,返回name,field,fieldMeta 对象

    • onCollectCommon: function onCollectCommon(
          name, // 字段名称
          action, // 事件
          args // 事件event 参数
          ) {
          // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
          var fieldMeta = this.fieldsStore.getFieldMeta(name);
          console.log('fieldMeta=',fieldMeta)
          console.log('action=',fieldMeta)
           
          // 判断fieldMeta 中有 事件么 如果有有则执行事件
          if (fieldMeta[action]) {
            // 执行onChange方法
            fieldMeta[action].apply(
              fieldMeta,
              // 数组去重
              _toConsumableArray(args)
            );
          } else if (
            //原始组件的的props 属性
            fieldMeta.originalProps &&
            //原始组件的的props 属性 事件
            fieldMeta.originalProps[action]
          ) {
            var _fieldMeta$originalPr;
            // 执行onChange
            (_fieldMeta$originalPr = fieldMeta.originalProps)[action].apply(
              _fieldMeta$originalPr,
              // 数组去重
              _toConsumableArray(args)
            );
          }
          //从原生dom onChange事件中获取值
          var value = fieldMeta.getValueFromEvent
            ? fieldMeta.getValueFromEvent.apply(
                fieldMeta,
                // 数组去重
                _toConsumableArray(args)
              )
            : getValueFromEvent.apply(
                undefined,
                // 数组去重
                _toConsumableArray(args)
              );
          // 如果表单有传递onValuesChange 函数进来 则触发
          if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) {
            // 获取所有值
            var valuesAll = this.fieldsStore.getAllValues();
            var valuesAllSet = {};
            valuesAll[name] = value;
            // 循环所有值
            Object.keys(valuesAll).forEach(function (key) {
              //设置值
              return set(valuesAllSet, key, valuesAll[key]);
            });
            // 更新值
            onValuesChange(
              // 浅拷贝
              _extends(
                // 为对象添加 描述设置属性 或者是为对象添加 属性或者方法
                _defineProperty({}, formPropName, this.getForm()),
                this.props
              ),
              // 设置值
              set({}, name, value),
              // 原来所有值对象
              valuesAllSet
            );
          }
          // 获取字段
          var field = this.fieldsStore.getField(name);
          return {
            // 字段名称
            name: name,
            // 合并新的字段
            field: _extends({}, field, { value: value, touched: true }),
            // 字段存储对象
            fieldMeta: fieldMeta,
          };
        },
    •  

    validateFieldsInternal

    • 验证字段函数

    • 收集验证 onchange 事件 ,调用 "async-validator"校验插件,收集是否有error信息,然后存储到fieldMeta对象中。

    • 然后调用调用 setFields 设置字段值

        //字段内部验证字段
        validateFieldsInternal: function validateFieldsInternal(
          fields, // 需要校验的字段
          _ref, // 拓展参数选项
          callback // 回调函数
        ) {
          var _this7 = this;

          var fieldNames = _ref.fieldNames, // 字段名称
            action = _ref.action, // 字段事件 一般为onchange
            _ref$options = _ref.options, // getFieldDecorator 参数
            options = _ref$options === undefined ? {} : _ref$options;

          var allRules = {}; // 校验规则
          var allValues = {}; // 值
          var allFields = {}; //字段
          var alreadyErrors = {}; // 错误信息
          // 循环字段
          fields.forEach(function (field) {
            // 获取字段名称
            var name = field.name;
            if (options.force !== true && field.dirty === false) {
              // 字段错误信息
              if (field.errors) {
                // 如果有错误信息存起来
                set(alreadyErrors, name, { errors: field.errors });
              }
              return;
            }
            // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
            var fieldMeta = _this7.fieldsStore.getFieldMeta(name);
            //浅拷贝字段
            var newField = _extends({}, field);
            //设置新的字段错误信息为undefined
            newField.errors = undefined;
            // 设置已经验证过
            newField.validating = true;
                //
            newField.dirty = true;
            //获取得到验证规则
            allRules[name] = _this7.getRules(fieldMeta, action);
            // 获取值
            allValues[name] = newField.value;
            //字段名称
            allFields[name] = newField;
          });
          // 设置字段
          this.setFields(allFields);
          // in case normalize 以防正常化 获取全部值
          Object.keys(allValues).forEach(function (f) {
            // 获取值
            allValues[f] = _this7.fieldsStore.getFieldValue(f);
          });
          //判断对象是否是空对象
          if (callback && isEmptyObject(allFields)) {
            callback(
              isEmptyObject(alreadyErrors) ? null : alreadyErrors,
              // 字段值
              this.fieldsStore.getFieldsValue(fieldNames)
            );
            return;
          }
           
          // 表单异步验证插件
          var validator = new AsyncValidator(allRules);
          //整个表单校验信息 一般不会传递这个
          if (validateMessages) {
            validator.messages(validateMessages);
          }
          console.log('allRules=',allRules)
          console.log('allValues=',allValues)
          validator.validate(
            allValues, // 全部值
            options, // 选项
            // 错误信息回调函数
            function (errors) {
              // 获取错误信息集合
              var errorsGroup = _extends({}, alreadyErrors);
              // 如果错误信息存在
              if (errors && errors.length) {
                // 循环错误信息
                errors.forEach(function (e) {
                  //获取字段
                  var errorFieldName = e.field;

                  var fieldName = errorFieldName;

                  // Handle using array validation rule. 句柄使用数组验证规则。
                  // ref: https://github.com/ant-design/ant-design/issues/14275
                  //如果有一个元素满足条件,则表达式返回true , 剩余的元素不会再执行检测。
                  Object.keys(allRules).some(function (ruleFieldName) {
                    var rules = allRules[ruleFieldName] || [];

                    // Exist if match rule 如果匹配规则存在
                    if (ruleFieldName === errorFieldName) {
                      fieldName = ruleFieldName;
                      return true;
                    }

                    // Skip if not match array type 如果不匹配数组类型,则跳过
                    if (
                      //如果全部元素满足条件,则表达式返回true ,
                      rules.every(function (_ref2) {
                        var type = _ref2.type;
                        return type !== "array";
                      }) ||
                      // 检查 xxx.
                      errorFieldName.indexOf(ruleFieldName + ".") !== 0
                    ) {
                      return false;
                    }

                    // Exist if match the field name 如果匹配字段名称,则存在
                    var restPath = errorFieldName.slice(ruleFieldName.length + 1);
                    if (/^d+$/.test(restPath)) {
                      fieldName = ruleFieldName;
                      return true;
                    }

                    return false;
                  });
                  // 获取字段
                  var field = get(errorsGroup, fieldName);
                  if (typeof field !== "object" || Array.isArray(field)) {
                    // 记录错误字段
                    set(errorsGroup, fieldName, { errors: [] });
                  }
                  var fieldErrors = get(errorsGroup, fieldName.concat(".errors"));
                  //收集错误信息
                  fieldErrors.push(e);
                });
              }
              var expired = [];
              var nowAllFields = {};
              // 循环校验规则
              Object.keys(allRules).forEach(function (name) {
                //获取错误字段
                var fieldErrors = get(errorsGroup, name);
                // 获取当前字段
                var nowField = _this7.fieldsStore.getField(name);
                // avoid concurrency problems 避免并发问题
                //判断两个值是否相等
                if (!eq(nowField.value, allValues[name])) {
                  // 如果不相等
                  expired.push({
                    name: name,
                  });
                } else {
                  //如果相等
                  nowField.errors = fieldErrors && fieldErrors.errors;
                  nowField.value = allValues[name];
                  nowField.validating = false;
                  nowField.dirty = false;
                  nowAllFields[name] = nowField;
                }
              });
              // 设置字段
              _this7.setFields(nowAllFields);
              if (callback) {
                //如果有值不相等,则需要重新校验一次
                if (expired.length) {
                  expired.forEach(function (_ref3) {
                    var name = _ref3.name;

                    var fieldErrors = [
                      {
                        message: name + " need to revalidate", //需要重新验证
                        field: name,
                      },
                    ];
                    // 记录是否有错误信息
                    set(errorsGroup, name, {
                      expired: true,
                      errors: fieldErrors,
                    });
                  });
                }
                // 回调函数
                callback(
                  isEmptyObject(errorsGroup) ? null : errorsGroup,
                  _this7.fieldsStore.getFieldsValue(fieldNames)
                );
              }
            }
          );
        },

     

     

    setFields 设置form表单值

    • 参数:对象key与value。重新设置表单值,

    • 通过循环遍历form表单值新旧值对比,如果不同则更新

     function setFields(fields) {
          var _this = this;
          // 获取字段信息
          var fieldsMeta = this.fieldsMeta;
          // 新字段 和 原来字段合并
          var nowFields = _extends({}, this.fields, fields);
          // 新的值
          var nowValues = {};
          // 获取字段值
          Object.keys(fieldsMeta).forEach(function (f) {
            // 获取字段的值
            nowValues[f] = _this.getValueFromFields(
              f, // 字段名称
              nowFields // 所有字段
            );
          });
          // 循环现在的值 然后注册到Meta 中
          Object.keys(nowValues).forEach(function (f) {
            // 获取单个值
            var value = nowValues[f];
            // 获取单个字段的getFieldMeta 对象 这个是字段 信息
            var fieldMeta = _this.getFieldMeta(f);
            // 初始化值设定的一个函数 demo https://codepen.io/afc163/pen/JJVXzG?editors=0010
            if (fieldMeta && fieldMeta.normalize) {
              // 获取字段的值
              //当前值
              var nowValue = fieldMeta.normalize(
                value,
                _this.getValueFromFields(f, _this.fields),
                nowValues
              );
              //如果新的值和旧的值不相同则更新新的值
              if (nowValue !== value) {
                nowFields[f] = _extends({}, nowFields[f], {
                  value: nowValue,
                });
              }
            }
          });
          console.log('this.fields=', this.fields)
            debugger
          // 设置 字段
          this.fields = nowFields;
        },

     

     

    validateFields 表单提交 校验所有表单值。

    • 表单提交前做做校验。

    • 获取到参数通过getParams格式处理参数,这样让函数接口兼容性更强

    • 然后调用validateFieldsInternal去做校验

    • callback 返回表单值

           //验证字段,返回promise
          validateFields: function validateFields(ns, opt, cb) {
            var _this8 = this;
            console.log("this=", this);
            console.log("this.fieldsStore=", this.fieldsStore);

         

            var pending = new Promise(function (resolve, reject) {
              // 得到参数,格式化整理转义参数
              var _getParams = getParams(ns, opt, cb),
                // 获取参数的names
                names = _getParams.names,
                // 获取参数的options 选项
                options = _getParams.options;
              // 得到参数,格式化整理转义参数
              var _getParams2 = getParams(ns, opt, cb),
                // 获取参数的回调函数
                callback = _getParams2.callback;
              // 如果回调函数
              if (!callback || typeof callback === "function") {
                var oldCb = callback;
                callback = function callback(errors, values) {
                  if (oldCb) {
                    // 执行回调函数
                    oldCb(errors, values);
                  }
                  if (errors) {
                    // 如果有错误则执行reject
                    reject({ errors: errors, values: values });
                  } else {
                    // 成功执行
                    resolve(values);
                  }
                };
              }
              // 获取字段名称       从所有字段中 过滤出 maybePartialName 参数匹配到的字段
              var fieldNames = names
                ? _this8.fieldsStore.getValidFieldsFullName(names)
                : _this8.fieldsStore.getValidFieldsName();
              // 获取含有检验规则的字段
              var fields = fieldNames
                .filter(function (name) {
                  // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
                  var fieldMeta = _this8.fieldsStore.getFieldMeta(name);
                  //含有校验规则的字段
                  return hasRules(fieldMeta.validate);
                })
                .map(function (name) {
                  //获取字段
                  var field = _this8.fieldsStore.getField(name);
                  // 获取字段的值
                  field.value = _this8.fieldsStore.getFieldValue(name);
                  // 返回字段
                  return field;
                });
              console.log("validateFields fields=", fields);
              // 如果没有校验字段
              if (!fields.length) {
                // 获取字段值
                callback(null, _this8.fieldsStore.getFieldsValue(fieldNames));
                return;
              }
              // 标志当某一规则校验不通过时,是否停止剩下的规则的校验
              if (!("firstFields" in options)) {
                options.firstFields = fieldNames.filter(function (name) {
                  // 获取单个字段的getFieldMeta 对象 这个是字段 信息 和设置 Meta 初始化值作用
                  var fieldMeta = _this8.fieldsStore.getFieldMeta(name);
                  return !!fieldMeta.validateFirst; //当某一规则校验不通过时,是否停止剩下的规则的校验
                });
              }
              //字段校验
              _this8.validateFieldsInternal(
                fields,
                {
                  fieldNames: fieldNames,
                  options: options,
                },
                callback
              );
            });
            //俘获错误
            pending["catch"](function (e) {
              // eslint-disable-next-line no-console
              if (console.error && process.env.NODE_ENV !== "production") {
                // eslint-disable-next-line no-console
                console.error(e);
              }
              return e;
            });
            return pending;
          },

       

    •  

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    页面表单里的图片上传ENCTYPE="multipart/form-data"
    OSGI
    httpClient使用中报错org.apache.commons.httpclient.HttpMethodBase
    DNSPod--国内最早提供免费智能DNS产品的网站,致力于为各类网站提供高质量的多线智能DNS免费解析
    spring security 一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架
    Unable to parse request org.apache.commons.fileupload.FileUploadBase$IOFileUploadException: Processing of multipart/form-data request failed. null
    swfupload 上传报 security error # 2049 (security) 安全错误问题
    如何强制指定输入的参数必须为数字
    弹性盒子模型子元素垂直和水平居中
    Git常见错误处理
  • 原文地址:https://www.cnblogs.com/hao123456/p/15165127.html
Copyright © 2020-2023  润新知