当前位置: 首页 > Web前端 > JavaScript

Form在Datastack中的应用(下):深度篇

时间:2023-03-27 16:36:20 JavaScript

本文的主题是Form在Datastack产品中使用后的理解消化过程。通过介绍Form中一些常用的方法,来了解一些设计思路,加深我们对技术的追求。主要介绍Form表单的创建和Form表单的双向绑定(getFieldDecorator)。下面提到的Form表单都是Antd3.x中的Form组件,以下简称Form表单。Form在数栈中的应用(上):验证中提到,我们生在最好的时代。其实别人造轮子是为了帮我们做一些事情。今天就来看看吧。别人的轮子是怎么造的,我们自己能不能实现。关注过Antd的同学可能会有这样的印象,Antd是基于react-component组件进行UI封装的,本文将主要关注react-component/form的代码。1、别人的Form1.1的From.create,先查看createForm.js文件。该文件主要封装了createBaseForm.js文件,并添加了一些常用的方法。importcreateBaseFormfrom'./createBaseForm';exportconstmixin={getForm(){return{getFieldsValue:this.fieldsStore.getFieldsValue,getFieldValue:this.fieldsStore.getFieldValue,...validateFields:this.validateFields,resetFields:this.重新设置领域,};},};functioncreateForm(options){returncreateBaseForm(options,[mixin]);}exportdefaultcreateForm;接下来查看createBaseForm.js文件,主要查看文件中的createBaseForm方法,该方法起到装饰器的作用,在props中包装了一个默认为form的变量,在这个变量中完成Form的所有功能。createBaseForm的作用是复制当前传入的组件,即调用函数将当前组件作为被包装组件传递,最后返回一个具有新属性的被包装组件。render(){const{wrappedComponentRef,...restProps}=this.props;//eslint-disable-lineconstformProps={//getForm方法来自createForm.js,在props中包裹一个formPropName变量,默认为form[formPropName]:this.getForm(),};//获取表单实例if(withRef){formProps.ref='wrappedComponent';}elseif(wrappedComponentRef){formProps.ref=wrappedComponentRef;}constprops=mapProps.call(this,{...formProps,...restProps,});return;}装饰器(decorator):是类相关的语法,主要用来修饰类和类的方法(类属性),大多数面向对象的编程语言都支持这种语法,例如Java、Python。装饰器可以简单理解为:它可以修改一些对象,然后返回一个被包装的对象。综合起来,Form.create(options)其实就是把我们的业务组件封装了一次,初始化了Form相关的属性,挂载了一些需要用到的方法,并将这些方法添加到props.form中。1.2getFieldDecorator{getFieldDecorator('name',{initialValue:userInfo.name,rules:[{required:true,message:'Namecannotbeempty!'}]})()}从上面的代码和下面的实现方法可以看出getFieldDecorator是一个柯里化函数,通过输入id和parameters组件是一个Dom节点,用于输入新的属性,并将option的各种props如valuePropName、getValueProps、initialValue、rules等挂载到输入组件中。getFieldDecorator(name,fieldOption){constprops=this.getFieldProps(name,fieldOption);returnfieldElem=>{//如果字段被渲染,我们应该将它放入记录中this.renderFields[name]=true;constfieldMeta=this.fieldsStore.getFieldMeta(name);constoriginalProps=fieldElem.props;fieldMeta.originalProps=originalProps;fieldMeta.ref=fieldElem.ref;constdecoratedFieldElem=React.cloneElement(fieldElem,{...props,//没有initialValueundefined,如果有,就是initialValue的值...this.fieldsStore.getFieldValuePropValue(fieldMeta),});返回supportRef(fieldElem)?(decoratedFieldElem):({decoratedFieldElem});};}getFieldDecorator有如下两个功能,可以在createBaseForm.js文件的getFieldProps和getFieldValuePropValue方法中验证:初始化数据字段时将数据字段放入fieldsStore;将props挂载到input组件上传时会从fieldsStore中读取数据字段。1.3validateFields通常使用validateFields方法来验证我们的表单数据。查看createBaseForm.js文件中validateFields方法的实现,发现validateFields方法返回一个Promise,并组装了validateFieldsInternal方法需要的参数。validateFields(ns,opt,cb){constpending=newPromise((resolve,reject)=>{...this.validateFieldsInternal(...,params,callback);});...返回待定;}再看validateFieldsInternal方法的代码,它会从fieldsStore中获取rules和data字段的值,校验通过后将错误信息存储到对应的fieldsStore中。importAsyncValidatorfrom'async-validator';validateFieldsInternal(fields,{fieldNames,action,options={}},callback,){constfieldMeta=this.fieldsStore.getFieldMeta(name);...constvalidator=newAsyncValidator(allRules);validator.validate(allValues,options,errors=>{if(errors&&errors.length){errors.forEach(e=>{...constfieldErrors=get(errorsGroup,fieldName.concat('.errors'));fieldErrors.push(e);});}});...this.setFields(nowAllFields);...}一般来说,Form表单从初始化到表单集合验证,经历了以下几个步骤:1.通过Form.create方法将一些属性初始化到props.form中,供开发者调用;2.通过getFieldDecorator初始化表单的属性和值,达到双向绑定的效果;3、校验通过,将数据保存到fieldsStore;如果验证失败,则将错误保存在fieldsStore中并渲染。2.自己的Form效果和代码可以查看https://stackblitz.com/edit/r...2.1getFieldDecorator/***实现getFieldDecorator方法*初始化时将initialValue赋给输入框的值*可以在输入框变化时获取值*/constgetFieldDecorator=(key:string,options:any)=>{//判断是否第一次赋值避免无限循环constfirst=Object.keys(formData).indexOf(key)===-1;if(options.rules){rules[key]=[...options.规则];}if(first&&options.initialValue){setFormData({...formData,[key]:options.initialValue});}return(formItem)=>{if(errObj[key]){formItem={...formItem,props:{...formItem.props,className:'inputerr'},};}return({React.cloneElement(formItem,{name:key,value:formData[key]||'',onChange:(e:any)=>{//删除输入框的值改变时的错误提示:()=>{//当Validate时默认为blurvalidateFields();},})}{errObj[key]||''}

);};};2.2validateFields//绑定验证方法constvalidateFields=(cb?:any)=>{leterrObjTemp={};Object.keys(rules).forEach((key)=>{rules[key].forEach((rule)=>{if(rule?.required&&(!formData[key]||formData[key].trim()==='')){errObjTemp={...errObjTemp,[key]:rule?.message||`${key}isrequired!`,};setErrObj(errObjTemp);}});});cb&&cb(Object.keys(errObjTemp).length?errObjTemp:undefined,formData);};2.3createFormconstcreateForm=(FormFunc)=>(props)=>{const[formData,setFormData]=useState({});const[errObj,setErrObj]=useState({});const规则={};...//在props上挂载自定义方法returnFormFunc({...props,getFieldDecorator,validateFields});};

最新推荐
猜你喜欢