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;
        },

     

  •  

 

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM