一、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>
)
}
}
上面我们输入一直校验,这是因为
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: '兄弟你忘记填这项了!'
}
]
}
测试效果很好:
补充:
昨天刚演示的这个案例,虽然能通过案例来知道它的用法,但是不知道这个方法的精髓。恰好今天想到个牛叉的案例。身份证和姓名人证匹配查询案例
后台查询的接口是在阿里买的,使用他们提供的代码,因为我只懂 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('身份证信息不正确!');
}
}
六、验证表单所有域的正确性
有张表单需要用户填写,结果用户没写或有的没写,想直接跳到下一步,这时就得给出必要的提示。
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 密令和短信验证码再次请求服务器,接收服务器的响应。
整个过程,鼠标离开第二个输入框,触发验证码匹配事件。
<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>