前言
在实际项目中我们时常有可能需要Ip地址输入框,键值对输入框这样的复杂输入组件。但是ant design
官方并没有给出这样的组件,文档中也没有提到应该如何写出这样的组件。
我在研究了一番实现了该功能,在这里与大家分享一下,希望可以方便到后来人。
源码分享
对于不需要教程的同学可以直接查看源码:
教程-编写一个IP输入组件
第一步:完全受控组件与ant design表格组件联动
首先我们需要建立一个完全受控的输入组件,并且该组件可以嵌套进ant design的表格组件当中并正常
运行。
{getFieldDecorator('ip')(
<IpInput />
)}
IpInput组件代码:
import React, {Component} from 'react';
import {Input} from "antd";
export default class IpInput extends Component {
constructor(props) {
super(props);
this.state = {
ip: '',
}
}
hdlInputChange = (e) => {
this.setState({ip: e.target.value})
this.props.onChange({target: {value: e.target.value}})
}
render() {
return (
<div>
<Input value={this.state.ip} onChange={this.hdlInputChange} />
</div>
);
}
}
第二步:在IpInput组件中建立多个Input,并联动
重点是输出值的拆分与聚合
hdlInputChange = (e, block) => {
let ipAdressArr = [this.state.ablock, this.state.bblock, this.state.cblock, this.state.dblock]
let value = e.target.value
this.setState({[`${block}block`]: value})
ipAdressArr[blockDict[block]] = value
this.props.onChange({target: {value: ipAdressArr.join('.')}})
}
详细代码请看:CodeSandbox
到这一步一个基本的ip Input
输入组件已经成型,但是难点部分还未开始。
第三步:校验规则处理
如果现在我们就开始正常使用该组件,4个输入框的报错样式必定是同时出现的。一个是红框的话,其他
三个也必定是红框状态。这是ant design
的程序设计,FormItem
的报错样式由外层容器通过CSS控制。
上面这段话不容易理解的话自己试一下就明白了。
也就是说我们需要单独控制4个Input框的校验状态,已经有数字的应为正确状态,没有数字的校验时显示为
红色。且这个校验行为要能够被ant design
的Form
组件触发。
首先我们建立一个类似ant design
原生的Form.Item
组件用来包裹每个Input
并负责校验逻辑。
class FromItemValidatorWarpper extends Component {
constructor(props) {
super(props)
this.state = {
validateStatus: ''
}
}
componentDidMount () {}
componentDidUpdate (prevProps, prevState) {
if(this.props.valiating && prevProps.validating !== this.props.valiating){
// form 触发的 validating
let validateStatus = ''
if(!this.getChildProp("value")){
validateStatus = 'error'
}
if(this.state.validateStatus !== validateStatus){
this.setState({validateStatus})
}
}
}
getChildProp(prop) {
const child = this.props.children
return child && child.props && child.props[prop];
}
render() {
return (
<Form.Item
validateStatus={this.state.validateStatus}
>
{this.props.children}
</Form.Item>
)
}
}
然后用该组件包裹IpInput
组件
<FromItemValidatorWarpper valiating={this.state.valiating}>
<Input value={this.state.dblock} onChange={(e)=>{this.hdlInputChange(e, 'd')}} />
</FromItemValidatorWarpper>
在IpInput
组件中建立valiating
属性,并使其和外层ant design Form
组件的validator
联动。
componentDidUpdate(prevProps) {
let dataField = this.props["data-__field"]
if(dataField.errors && !prevProps["data-__field"].errors){
// valitor 函数触发报错
this.setState({valiating: true})
}
if(!dataField.errors && prevProps["data-__field"].errors){
// valitor 函数触发清除报错
this.setState({valiating: false})
}
}
最后在使用IpInput
的组件位置添加一个正则校验。
{getFieldDecorator('ip', {
rules: [
{required: true, message: 'Please input your ip!'},
{
pattern: /((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))/,
message: 'Please finish your ip!'
}
],
})(
<IpInput/>
)}
OK,我们现在只差最后一步了,即在外层使用组件时使用setFieldsValue
初始化组件值的功能。
第四步:setFieldsValue
方法支持
componentDidUpdate
方法中加入一段代码判断组件上级value是否和内部value相同,不同且没有进行
初始化时进行初始化。
if(dataField.value !== [this.state.ablock, this.state.bblock, this.state.cblock, this.state.dblock].join('.') && !this.initialized){
this.initialized = true
let ipAdressArr = dataField.value.split('.')
this.setState({
ablock: ipAdressArr[0],
bblock: ipAdressArr[1],
cblock: ipAdressArr[2],
dblock: ipAdressArr[3],
})
}
结尾
以上,一个IP输入组件基本完成了。细节包括样式还有很多可以优化的地方,我在这里就不继续了。maybe
以后再来更新。
我把最后的完整代码放在github上,有任何建议可
以给我提交issue或下面评论回复,谢谢。