基于Formik框架实现增减按钮组并改造TextInputField及验证
扩展Formik表单实现带增减按钮的数值输入组件
需求概述
需要为Formik表单框架添加一个支持增减操作的数值输入组件,要求:
- 整合现有的增减按钮组功能
- 允许直接输入数值,替代原有的只读按钮展示
- 实现数值范围验证(限制在指定最大/最小值内)
- 适配现有的
TextInputField组件结构
现有代码参考
增减按钮组组件
import React from "react"; import Button from "@material-ui/core/Button"; import ButtonGroup from "@material-ui/core/ButtonGroup"; class GroupedButtons extends React.Component { state = { counter: 0 }; handleIncrement = () => { this.setState((state) => ({ counter: state.counter + 1 })); }; handleDecrement = () => { this.setState((state) => ({ counter: state.counter - 1 })); }; render() { return ( <ButtonGroup size="small" aria-label="small outlined button group"> <Button onClick={this.handleDecrement}>-</Button> <Button disabled>{this.state.counter}</Button> <Button onClick={this.handleIncrement}>+</Button> </ButtonGroup> ); } } export default GroupedButtons;
待改写的TextInputField组件
import React, { Component } from 'react'; import TextField from '@mui/material/TextField'; import InputAdornment from '@mui/material/InputAdornment'; class TextInputField extends Component { constructor(props, context) { super(props, context); } render() { return ( <TextField fullWidth={true} type={this.props.item.type} label={this.props.item.label} placeholder={this.props.item.placeholder} InputLabelProps={this.props.item.placeholder? {shrink: true} : {}} InputProps={{ startAdornment: this.props.item.startAdornment? <InputAdornment position="start">{this.props.item.startAdornment}</InputAdornment>: null, endAdornment: this.props.item.endAdornment? <InputAdornment position="end">{this.props.item.endAdornment}</InputAdornment>: null }} inputProps={{ maxLength: this.props.item.charLimit? this.props.item.charLimit:null, autoComplete: this.props.item.autoComplete? this.props.item.autoComplete:"off" }} rows={(this.props.item.type === "comment") ? 6 : null} multiline={(this.props.item.type === "comment") ? true : false} disabled={this.props.item.disabled} {...this.props.field} onChange={event => { this.props.form.setFieldValue(this.props.name, event.target.value); this.props.onHandle(this.props.name, event.target.value); }} error={this.props.meta.touched && (this.props.meta.error && this.props.meta.error.length > 0 ? true : false)} /> ) } } export default TextInputField
改写后的实现方案
下面是整合了增减按钮、直接输入和范围验证的Formik适配组件:
import React, { Component } from 'react'; import TextField from '@mui/material/TextField'; import InputAdornment from '@mui/material/InputAdornment'; import Button from "@material-ui/core/Button"; import ButtonGroup from "@material-ui/core/ButtonGroup"; class NumericInputField extends Component { // 处理数值合法性校验 validateValue = (value) => { const { min = 0, max = Infinity } = this.props.item; let numValue = parseInt(value); // 空值或非数字设为最小值 if (isNaN(numValue)) { numValue = min; } // 限制在最大最小值范围内 numValue = Math.max(min, Math.min(max, numValue)); return numValue.toString(); }; // 增减操作处理 handleChangeCount = (step) => { const { form, name } = this.props; const currentValue = parseInt(form.values[name]) || this.props.item.min || 0; const newValue = currentValue + step; const validatedValue = this.validateValue(newValue); form.setFieldValue(name, validatedValue); this.props.onHandle(name, validatedValue); }; // 输入框值变化处理 handleInputChange = (event) => { const { form, name } = this.props; const validatedValue = this.validateValue(event.target.value); form.setFieldValue(name, validatedValue); this.props.onHandle(name, validatedValue); }; render() { const { item, field, meta } = this.props; // 仅当类型为数值时显示增减按钮 const isNumericType = item.type === 'number'; return ( <TextField fullWidth={true} type={isNumericType ? 'number' : item.type} label={item.label} placeholder={item.placeholder} InputLabelProps={item.placeholder ? { shrink: true } : {}} InputProps={{ startAdornment: item.startAdornment ? <InputAdornment position="start">{item.startAdornment}</InputAdornment> : null, endAdornment: isNumericType ? ( <InputAdornment position="end"> <ButtonGroup size="small" aria-label="numeric adjust button group"> <Button onClick={() => this.handleChangeCount(-1)} disabled={parseInt(field.value) <= (item.min || 0)} >-</Button> <Button onClick={() => this.handleChangeCount(1)} disabled={parseInt(field.value) >= (item.max || Infinity)} >+</Button> </ButtonGroup> </InputAdornment> ) : ( item.endAdornment ? <InputAdornment position="end">{item.endAdornment}</InputAdornment> : null ) }} inputProps={{ maxLength: item.charLimit ? item.charLimit : null, autoComplete: item.autoComplete ? item.autoComplete : "off", min: item.min, max: item.max }} rows={(item.type === "comment") ? 6 : null} multiline={(item.type === "comment") ? true : false} disabled={item.disabled} {...field} onChange={this.handleInputChange} error={meta.touched && !!meta.error} helperText={meta.touched && meta.error} /> ); } } export default NumericInputField;
关键改进点
- 整合增减按钮:通过
InputAdornment将按钮组添加到输入框右侧,仅当字段类型为number时显示 - 数值验证:
- 输入非数字时自动修正为最小值
- 限制数值在
item.min和item.max范围内 - 增减按钮在达到边界时自动禁用
- Formik适配:直接调用Formik的
setFieldValue更新表单状态,同时触发外部onHandle回调 - 向后兼容:保留原
TextInputField的所有功能,仅对数值类型字段增强
内容的提问来源于stack exchange,提问作者The Old County
相关产品推荐
相关产品推荐

