React组件化-03-Antd表单封装之字段包装及表单项事件实现(1)

263 阅读4分钟

1.Antd表单封装的字段包装:

这里简单梳理下整个执行过程思路,方便日后复习:

  1. MFormCreate组件作为装饰器,包装 MForm
  2. 通过解构赋值 const {getFieldDecorator} = this.props.form;获得了 MFromCreate传递的form对象(键值对的value是函数)
  3. getFieldDecorator函数是一个 高阶函数,返回的函数接收一个Jsx
    1. React.cloneElement():克隆并返回一个新的 ReactElement(内部子元素也会跟着克隆),接收 3个参数
    2. 参数①:用于克隆的母体React元素(必选)
    3. 参数②:为克隆后生成的React元素添加新的props,或覆盖从母体中克隆而来的部分或全部props。(可选)
    4. 参数③:为新生成的React元素添加新的children,取代从母体中克隆而来的children
  4. 然后执行到 onChange 事件
  5. 接着,在onChange事件绑定的 handleChange 方法中修改 state状态值
  6. setState 函数参数的第二个参数的函数中去对最新修改修改的值做校验
// MformCreate.js
import React, {Component} from 'react';

const MFormCreate = Comp =>{
    return class extends Component{
       constructor(props) {
           super(props);
           this.options = {};// 各个字段的选项值 它的变化不会影响组件的重新渲染
           this.state = {}; // 各个字段的值 他的变化 要触发校验的函数
           this.form  = this.form.bind(this);
           this.getFieldDecorator = this.getFieldDecorator.bind(this);
           this.handleChange = this.handleChange.bind(this);
           this.validateFiled = this.validateFiled.bind(this);
       }
       //处理表单项的输入事件
       handleChange(e){
            const {name,value} = e.target;
            console.log("我是name:",name,"我是值",value);
            this.setState({
              [name]:value
            },()=>{
                //🚀 设置完之后要校验各个字段
                this.validateFiled(name);
            })
       }
      // 🌟 校验(下面会重新提及)
       validateFiled(filedName){
            console.log("校验啦",filedName);
       }
       // 🚀 getFieldDecorator返回一个函数
       getFieldDecorator(filedName,options){
           //设置字段选项的配置
           this.options[filedName] = options;
           return (Jsx)=>{
                //🚀这里使用一种更加api的方式
               return (
                   <div>
                       {
                           //两个参数:①要克隆的元素;②对象属性
                           React.cloneElement(Jsx,{
                               name:filedName,//控件的name
                               value:this.state[filedName] || "", //控件的值
                               onChange:this.handleChange
                           })
                       }
                   </div>
               )
           }

       }
       //🚀 这里form函数调用后返回一个函数组成的对象,后续若有添加,拓展这个返回的对象即可
       form(){
           return(
               {
                   getFieldDecorator:this.getFieldDecorator
               }
           )
       }
       render() {
            return (
                <Comp {...this.props} form = {this.form()}> </Comp>
            )
       }
    }
}
//MForm.js

import React, {Component} from 'react';
import MFormCreate form "./Compontent";

@MFormCreate
class MForm extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(){
       // 校验各个字段的必填项是否正确
    }
    render() {
        const {getFieldDecorator} = this.props.form;
        return (
            <div>
                {
                    getFieldDecorator("username",{
                        rules:[
                            {
                                required:true,
                                message:"用户名为必填项目"
                            }
                        ]
                    })( <input type="text"/>)
                }
                {
                    getFieldDecorator("password",{
                        rules:[
                            {
                                required:true,
                                message:"密码为必填项目"
                            }
                        ]
                    })( <input type="password"/>)
                }
                {/*<input type="text"/>*/}
                {/*<input type="password"/>*/}
                <input type="button" value="登录" onClick={this.handleSubmit}/>
            </div>
        );
    }
}

export default MForm;

2.表单的单独项的校验:

  1. getFieldDecorator函数中通过 this.options[filedName] = options;完成对this.options对象的赋值,这个地方比较精髓
  2. handleChange中将输入的值作为参数传递给 validateFiled 中进行校验
  3. validateFiled 函数中对this.options 解构,然后利用规则进行判断。
    // validateFiled函数
//...
       validateFiled(filedName){
            console.log("校验啦",filedName);
            const {rules} = this.options[filedName];
            const ret = rules.some(rule=>{
                //🚀 required为true时则需要校验
                if(rule.required){
                    // 如果input的输入框没有值,设置显示的rule.message文字进行提示
                    if(!this.state[filedName]){
                       this.setState({
                           [filedName + "Message"]:rule.message
                       })
                        return true; //校验失败 返回true
                    }
                }
            })
           if(!ret){
               this.setState({
                   [filedName + "Message"]:""
               })
           }
           return !ret; //校验成功 返回false
       }
//...

3.表单提交按钮校验的实现方法:

  1. hanldeSubmit 方法开始看,返回的form对象中新添加了 validateFields方法,用于校验提交按钮
  2. 通过Object.keys(this.options) 拿到想要的key值组成的数组后,对每项进行单项的校验--validateFiled
  3. 最后将校验结果通过callback回调函数传递回去
  4. true 弹出成功的tipsfalse弹出失败的tips
//MFromCreate.js
import React, {Component} from 'react';

const MFormCreate = Comp =>{
    return class extends Component{
       constructor(props) {
           super(props);
           this.options = {};//各个字段的选项值 它的变化不会影响组件的重新渲染
           this.state = {}; //各个字段的值 他的变化 要触发校验的函数
           this.form  = this.form.bind(this);
           this.getFieldDecorator = this.getFieldDecorator.bind(this);
           this.handleChange = this.handleChange.bind(this);
           this.validateFiled = this.validateFiled.bind(this);
           this.validateFileds = this.validateFileds.bind(this);
       }
       //处理表单项的输入事件
       handleChange(e){
            const {name,value} = e.target;
            console.log("我是name:",name,"我是值",value);
            //setState是异步的
            this.setState({
              [name]:value
            },()=>{
                //🚀设置完之后要校验各个字段
                this.validateFiled(name);
            })
       }
       //🚀 单项目校验
       validateFiled(filedName){
            console.log("校验啦",filedName);
            const {rules} = this.options[filedName];
            const ret = rules.some(rule=>{
                //🚀 required为true时则需要校验
                if(rule.required){
                    // 如果input的输入框没有值,设置显示的rule.message文字进行提示
                    if(!this.state[filedName]){
                       this.setState({
                           [filedName + "Message"]:rule.message
                       })
                        return true;
                    }
                }
            })
           if(!ret){
               this.setState({
                   [filedName + "Message"]:""
               })
           }
           return !ret;
       }
       // 🚀 表单提交按钮的校验
        validateFileds(callback){
            //这个地方需要取到各个字段的值,然后对各个字段进行校验
            console.log("测试",Object.keys(this.options))
            const rets = Object.keys(this.options).map((filedName)=>{
                    return this.validateFiled(filedName);
                })
            //使用数组的every方法,如果所有的单项校验都为true,那么校验通过
            const res = rets.every(v=>v===true);
            callback(res);
        }
       //getFieldDecorator返回一个函数
       getFieldDecorator(filedName,options){
           //设置字段选项的配置
           this.options[filedName] = options;
           return (Jsx)=>{
                //🚀这里使用一种更加api的方式
               return (
                   <div>
                       {
                           //两个参数:①要克隆的元素;②对象属性
                           React.cloneElement(Jsx,{
                               name:filedName,//控件的name
                               value:this.state[filedName] || "", //控件的值
                               onChange:this.handleChange
                           })
                       }
                       {
                           this.state[filedName + "Message"] && (<p style={{color:'red'}}>{this.state[filedName + "Message"]}</p>)
                       }
                   </div>
               )
           }

       }
       //这里form函数调用后返回一个函数组成的对象
       form(){
           return(
               {
                   getFieldDecorator:this.getFieldDecorator,
                   validateFields:this.validateFileds 
               }
           )
       }
       render() {
            return (
                <Comp {...this.props} form = {this.form()}> </Comp>
            )
       }
    }
}
//MForm.js校验
import React, {Component} from 'react';
import MFormCreate form "./Compontent";

@MFormCreate
class MForm extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(){
       // 校验各个字段的必填项是否正确
        this.props.form.validateFields((isValid)=>{
            if(isValid){
                alert("验证成功~!")
            }else{
                alert("验证失败,请重新输入")
            }
        })
    }
    render() {
        const {getFieldDecorator} = this.props.form;
        return (
            <div>
                {
                    getFieldDecorator("username",{
                        rules:[
                            {
                                required:true,
                                message:"用户名为必填项目"
                            }
                        ]
                    })( <input type="text"/>)
                }
                {
                    getFieldDecorator("password",{
                        rules:[
                            {
                                required:true,
                                message:"密码为必填项目"
                            }
                        ]
                    })( <input type="password"/>)
                }
                {/*<input type="text"/>*/}
                {/*<input type="password"/>*/}
                <input type="button" value="登录" onClick={this.handleSubmit}/>
            </div>
        );
    }
}

export default MForm;

回调函数的用法真的是灰常nice~!︿( ̄︶ ̄)︿