antd 分步条和有验证的表单

一、antd Steps 步骤条基本使用:

基本代码实例:

import React, { Component } from 'react'
import { Steps } from 'antd';

const { Step } = Steps;
export default class S1 extends Component {
    render() {
        return (
            <div>
                <Steps current = {0}>
                    <Step title="第一步" description="步骤的详情描述,可选"/>
                    <Step title="第二步" status = "error"/>
                    <Step title="第三步" />
                </Steps>
            </div>
        )
    }
}

分步效果:


二、分步条制作对应的分页

每一步对应一个分页,应该采用信号量控制组件的形式核心代码是下面的 IIFE:

{
    (()=>{
        if(current === 0){
            return <S1 />
        }else if(current === 1){
            return <S2 />
        }else if(current === 2){
            return <S3 />
        }else if(current === 3){
            return <S4 />
        }
    })()
}

完整代码:

import { Steps, Button, message } from 'antd';

const { Step } = Steps;
import React, { Component } from 'react'
import S1 from "./S1";
import S2 from "./S2";
import S3 from "./S3";
import S4 from "./S4";
export default class S extends Component {
    constructor(){
        super();
        this.state = {
            current: 0
        };
    }
    next() {
        const current = this.state.current + 1;
        this.setState({ current });
    }

    prev() {
        const current = this.state.current - 1;
        this.setState({ current });
    }
    render() {
        const { current } = this.state;
        return (
            <div>
                <Steps current={current}>
                    <Step title="个人信息填写" />
                    <Step title="车辆信息" />
                    <Step title="照片上传" />
                    <Step title="成功" />
                </Steps>
                <div className="steps-content">
                    {
                        (()=>{
                            if(current === 0){
                                return <S1 />
                            }else if(current === 1){
                                return <S2 />
                            }else if(current === 2){
                                return <S3 />
                            }else if(current === 3){
                                return <S4 />
                            }
                        })()
                    }
                </div>
                <div className="steps-action">
                    {current < 3 && (
                    <Button type="primary" onClick={() => this.next()}>
                    下一步
                    </Button>
                    )}
                    {current >= 3 && (
                    <Button type="primary" onClick={() => message.success('已完成提交,请稍后!')}>
                    提交
                    </Button>
                    )}
                    {current > 0 && (
                    <Button style={{ marginLeft: 8 }} onClick={() => this.prev()}>
                    上一步
                    </Button>
                    )}
                </div>
            </div>
        )
    }
}
测试效果
五、Form 表单
  • 表单装饰
    官网案例:
class CustomizedForm extends React.Component {}

CustomizedForm = Form.create({})(CustomizedForm);

很明显 Form.create()()十个装饰器。如果项目装个插件:@babel/plugin-proposal-decorators 就可以使用语法糖来代替上面的写法成@Form.create()

  • 表单校验
    经 Form.create() 包装过的组件会自带 this.props.form 属性
const { getFieldDecorator } = this.props.form;

getFieldDecorator 用于和表单进行双向绑定,可以定义此表单是否是必填项,前面会加一个星号表示必填,还能校验输入是否正确。

import React, { Component } from 'react'
import { Form , Input , Col,Row} from 'antd';
@Form.create(
    { name: '第一个表单' }
)
export default class S1 extends Component {
    render() {
        // getFieldDecorator校验填写是否正确
        const { getFieldDecorator} = this.props.form;
        // <Form.Item {...formItemLayout} label="E-mail">
        // 让输入框和label里面的文字在同一水平面上
        const formItemLayout = {
            //  label 标签布局,同 <Col> 组件,设置 span offset 值
            labelCol: {
                xs: { span: 24 },
                sm: { span: 3 }
        },
        // 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol
            wrapperCol: {
                xs: { span: 24 },
                sm: { span: 6 },
            }
        };
        return (
            <div>
                <Form>
                    {/* label 是标签的文本*/}
                    <Form.Item {...formItemLayout} label="E-mail">
                        {
                            getFieldDecorator('email', {
                                rules: [
                                    {   
                                        // type定义输入的类型
                                        type: 'email',
                                        message: '逗我那,这个邮箱不能用,从新输入一个'
                                    },
                                    {   
                                        /*加星号,message忘记填的提示信息*/
                                        required: true,
                                        message: '兄弟你忘记填这项了!'
                                    }
                                ]
                            }
                        )(<Input />)
                        }
                    </Form.Item>
                </Form>
            </div>
        )
    }
}

实时校验.gif

上面我们输入一直校验,这是因为options.validateTrigger 校验子节点值的时机 默认为 onChange体验不好我们在 rule 更改校验子节点值的时机,填写完成在进行校验:

{
    getFieldDecorator('email', {
        rules: [
            {
                // type定义输入的类型
                type: 'email',
                message: '逗我那,这个邮箱不能用,从新输入一个'
            },
            
            {   
                /*加星号表示必填,message忘记填的提示信息*/
                required: true,
                message: '兄弟你忘记填这项了!'
            }
        ],
        validateTrigger:"onBlur"
    }
)(<Input />)
}

rules 里面包含了校验规则:

  • require true 或 false 这个表示是否是必填,外观上看有个星
  • type 内置校验 基本和 input 的 type 相同
  • pattern 正则表达式校验可替代 type
  • message 校验文案
  • validator: 自定义校验规则。
    validator 比较难这里演示下用法,这个自定义主要是用来检测比较偏僻的验证,这里以正则举例并不是太好,因为正则完全可以替换掉它,用来演示下用法还是无碍的:
{
getFieldDecorator('email', {
    rules: [
        {
            validator(rule, value, callback){
                if(!value){
                    // 什么都不输入的时候使用回调
                    // 来调用message的提示信息
                    callback();
                    return;
                }
                if(/^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(value)){
                    callback('邮箱填写正确!');
                }else{
                    // 输入不正确提示信息
                    callback('兄弟你写的邮箱不对!');
                }
            }
        },
        
        {   
            /*加星号表示必填,message忘记填的提示信息*/
            required: true,
            message: '兄弟你忘记填这项了!'
        }
    ]
}

测试效果很好:


validator: 自定义校验规则

补充:
昨天刚演示的这个案例,虽然能通过案例来知道它的用法,但是不知道这个方法的精髓。恰好今天想到个牛叉的案例。身份证和姓名人证匹配查询案例

后台查询的接口是在阿里买的,使用他们提供的代码,因为我只懂 PHP 和 nodeJS 所以可以从这两个中选择任意后台语言进行调试。

使用 PHP 写好代码,直接访问代码接口进行测试:

http://192.168.2.250:9027/check.php?idcard=321322198303183032&name=戚光明

程序返回的结果:

string(843) "HTTP/1.1 200 OK Server: Tengine Date: Thu, 22 Aug 2019 06:37:27 GMT Content-Type: application/json;charset=utf-8 Content-Length: 324 Connection: keep-alive Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With Access-Control-Max-Age: 172800 X-Ca-Request-Id: CA906DBE-2344-4B81-AD2C-F545FDF94B74 showapi_fee_num: 1 Access-Control-Allow-Credentials: true showapi_paycut: 1 { "showapi_res_error": "", "showapi_res_id": "4f9ec9db57bc480d8ff709da1f9a3325", "showapi_res_code": 0, "showapi_res_body": {"ret_code":0,"code":0,"msg":"匹配","birthday":"1983-03-18","sex":"M","address":"江苏宿迁市沭阳县"} } "

其中重要的字段是:"msg":"匹配"这就行了。

声明:姓名身份证是上网百度找的,请不要随便使用。如有侵权,联系删除。

然后使用 validator 。来实现下面功能。

人证匹配检测

源代码:正则验证输入内容,鼠标离开第二个框发送 Ajax 。获取第一个输入框的内容使用的是:
const { getFieldValue } = this.props.form;

validator(rule, value, callback){
    if(!value){
        // 什么都不输入的时候使用回调
        // 来调用message的提示信息
        callback();
        return;
    }
    if(/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value)){
        // 得到上个组件的值
        const name = getFieldValue("name");
        // 正则匹配成功发送公安部进行姓名和身份证匹配
        // 是否人证合一
        axios.get(`http://192.168.2.250:9027/check.php?idcard=${value}&name=${name}`).then(data=>{
        if(data.data.includes('"msg":"匹配"')){
            callback('姓名和身份证匹配!');
        }else{
            callback('提示你呀姓名和身份证不匹配!');
        }
    });
    }else{
        // 输入不正确提示信息
        callback('身份证信息不正确!');
    }
}
六、验证表单所有域的正确性

有张表单需要用户填写,结果用户没写或有的没写,想直接跳到下一步,这时就得给出必要的提示。


空表单提示.gif

S1 组件因为经过装饰器装饰,这个组件就会平白增加很多方法和属性。其中有个方法 validateFields() 就可以检查表单是否是正确填写,这个方法有个回调函数,函数的形参 res 就是记录返回的错误,如果没错误返回的结果 null ,是 null 我们就可以进入下一页了。

{current < 3 && (<Button type="primary" onClick={() => {
    if(current === 0){
        console.log(this.refs.s1)
        // validateFields可以检查组件是否全部验证正确
        // console.log(this.refs.s1.validateFields());直接返回一个Promise对象
        this.refs.s1.validateFields((res)=>{
            console.log(res);
            // 全部填完返回结果为null
            if(res === null){
                // 进入下一页
                this.next();
            }
        });
        // 
    }
}}>下一步</Button>)}
六、表单手机短信验证

前端接收到验证码发送给后端,后台验证密码的两种常见方式:

  • session 的验证,可以使用 PHP 打开 session ,发送 http 请求的时候带着session验证。
  • token 验证 为了密码的安全使用 md5 加密,前端请求的时候,后台响应一个 md5 加密密令(token),前端发送验证码的时候拿着 token 密令和短信验证码再次请求服务器,接收服务器的响应。
    整个过程,鼠标离开第二个输入框,触发验证码匹配事件。


    验证码.gif
<Form>
    {/* label 是标签的文本*/}
<Form.Item {...formItemLayout} label="手机号">
    {
        getFieldDecorator('phone', {
            rules: [
                {
                    // 正则匹配验证
                    pattern: /^[1]([3-9])[0-9]{9}$/,
                    message: '这是哪国的手机号,我怎么从没见过!'
                },
                {   
                    /*加星号表示必填,message忘记填的提示信息*/
                    required: true,
                    message: '兄弟你忘记填这项了!'
                }
            ],
            validateTrigger:"onBlur"
        }
    )(<Input />)
    }
    </Form.Item>
    {/* label 是标签的文本*/}
<Form.Item {...formItemLayout} label="验证码">
    <Row gutter={8}>
        <Col span={12}>
    {
        getFieldDecorator('VerificationCode', {
            rules: [
                {
                    validator:(rule, value, callback)=>{
                        if(!value){
                            // 什么都不输入的时候使用回调
                            // 来调用message的提示信息
                            callback();
                            return;
                        };
                        // 验证码是四位数
                        if(/^[0-9]{4}$/.test(value)){
                            // 验证输入的验证码是否正确
                            axios.get(`http://192.168.2.250:9027/b.php?yanzhengma=${value}&token=${this.state.token}`).then(data=>{
                                if(data.data == "ok"){
                                    callback("验证码正确!")
                                }else{
                                    callback("验证码错误请重新发送请求!")
                                }
                            });                                             
                        }else{
                            // 输入不正确提示信息
                            callback('验证码是0-9的四位数字');
                        }
                    }
                },                                  
                {   
                    /*加星号表示必填,message忘记填的提示信息*/
                    required: true,
                    message: '兄弟你忘记填这项了!'
                }
            ],
            validateTrigger:"onBlur"
        }
    )(<Input />)
    }
        </Col>
        <Col span={12}>
                <Button onClick = {()=>{
                    this.setState({
                        isShow : true
                    });
                    // 得到上个组件的值
                    const phone = getFieldValue("phone");
                    axios.get(`http://192.168.2.250:9027/a.php?phone=${phone}`).then(data=>{
                        this.setState({
                            token:data.data
                        })
                    });
                    this.timer = setInterval(()=>{
                        this.setState({
                            time : this.state.time - 1
                        });
                        if(this.state.time <= 0){
                            clearInterval(this.timer);
                            this.setState({
                                isShow : false,
                                time : 60
                            });
                        }
                    },1000);
                }} disabled = {this.state.isShow}>
                    {
                        !this.state.isShow ?
                        "发送验证码"
                        :
                        `重新发送 ${this.state.time}`
                    }
                </Button>
        </Col>
        </Row>
    </Form.Item>
</Form>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容