React - 实现一个基于 Antd 的数值范围组件

devtools/2024/10/20 6:18:25/

最近公司的产品需求要做一个数据采集流程,这个流程里面有比较多的表单数据,其中有一个输入数值范围的控件,这个功能还是很常见的,但是之前的开发没有封装成一个公共组件,特此自己造轮子。

需求原型

在这里插入图片描述

使用场景

当需求中需要录入数值范围的表单数据

实现思路

考虑到组件的共用性和拓展性,它应具备以下功能:

  • 只能输入数字,选择 InputNumber 数字输入框,并继承该组件的所有API属性
  • 当最小值大于最大值,或者最大值小于最小值时,应调换位置
  • 基于 自定义表单控件 封装

代码结构

由于这个功能实现还是比较简单的,组件的细节便不多描述,直接上代码:

/** @Author: 白雾茫茫丶<baiwumm.com>* @Date: 2023-12-13 14:34:55* @LastEditors: 白雾茫茫丶<baiwumm.com>* @LastEditTime: 2023-12-13 18:08:35* @Description: 数字范围输入组件*/
import { Col, InputNumber, Row } from 'antd'
import type { InputNumberProps } from 'antd/es/input-number'
import { gt, toNumber } from 'lodash'
import React, { FC, FocusEventHandler } from 'react'import type { EnumValues } from '@/utils/types'enum INPUT_TYPE {MIN, // 最小值MAX, // 最大值
}type InputType = EnumValues<typeof INPUT_TYPE>type ValuePair = (string | number | undefined)[];type FormDigitRangeProps = {value?: ValuePair; // 表单控件的值onChange?: (value: ValuePair) => void; // 表单控件改变值的回调separator: string; // 分割线separatorGap: number; // 分割线和数据框的 gapplaceholder: [string, string]; // 占位符suffix: string; // 后缀,不传则不显示
} & InputNumberPropsconst FormDigitRange: FC<FormDigitRangeProps> = ({value = [],onChange,separator = '~',separatorGap = 15,placeholder = ['最小值', '最大值'],precision = 2,min = 0,max = 99999999.99,suffix,...inputNumberProps
}) => {// 输入值失去焦点回调const handleChangeValue = (e: FocusEventHandler<HTMLInputElement>, type: InputType) => {// 获取输入框的值,这里转成 number 类型const result = e.target.value !== '' ? toNumber(e.target.value) : undefined;// 解构获取最值const [min, max] = value;switch (type) {case INPUT_TYPE.MIN:// 判断最小值是否大于最大值,为真就调换位置onChange?.(gt(result, max) ? [max, result] : [result, max])break;case INPUT_TYPE.MAX:// 判断最大值是否小于最小值,为真就调换位置onChange?.(gt(min, result) ? [result, min] : [min, result])break;}}// 渲染输入框const renderInputNumber = (type: InputType) => (<InputNumber{...inputNumberProps}min={min}max={max}value={toNumber(value[type])}precision={precision}placeholder={placeholder[type]}onBlur={(e) => handleChangeValue(e, type)}style={{ width: '100%' }}/>)return (<Row gutter={separatorGap} align='middle' wrap={false}><Col flex={1}>{renderInputNumber(INPUT_TYPE.MIN)}</Col><Col flex="none"><div>{separator}</div></Col><Col flex={1}>{renderInputNumber(INPUT_TYPE.MAX)}</Col>{suffix && (<Col flex="none">{suffix}</Col>)}</Row>)
}
export default FormDigitRange

代码不到100行,怎么样,是不是很容易?

使用方式

import { Button, Col, Form, Row, Space } from 'antd'
import { compact, isNumber } from 'lodash'
import React, { FC, useEffect, useState } from 'react'import PageContainer from '@/components/PageContainer'import FormDigitRange from './components/FormDigitRange'const DataAcquisition: FC = () => {const [form] = Form.useForm();const [fields, setFields] = useState({});const onFinish = (values: any) => {setFields(values)};useEffect(() => {form.setFieldValue('money', undefined)}, [])return (<PageContainer title="数字范围输入组件"><Form form={form} onFinish={onFinish}><Row><Col span={12}><Form.Itemname="money"label="租金涨跌金额"rules={[{ type: 'array', required: true, message: '' },() => ({validator(_, value) {if (!value || !compact(value).length) {return Promise.reject(new Error('请输入租金涨跌金额'));} else if (!isNumber(value[0])) {return Promise.reject(new Error('请输入最小值'));} else if (!isNumber(value[1])) {return Promise.reject(new Error('请输入最大值'));}return Promise.resolve();},}),]}><FormDigitRange suffix="元/㎡/月" /></Form.Item></Col></Row><Row><Col span={12}><Space direction="vertical" size="middle" style={{ display: 'flex' }} align='center'><pre style={{ background: '#f5f5f5', padding: '12px 20px', width: 400 }}>{JSON.stringify(fields, null, 2)}</pre><Button htmlType="submit" type="primary">提交</Button></Space></Col></Row></Form></PageContainer>)
}
export default DataAcquisition

参数说明

参数说明类型默认值是否必传
separator分隔符string~-
separatorGap分隔符间距number15-
placeholder占位符[string,string][‘最小值’, ‘最大值’]-
precision数值精度number2-
min最小值number0-
max最大值number99999999.99-
suffix后缀string--

除此之外支持所有 InputNumber属性

效果预览

在这里插入图片描述

注意事项

  1. 组件是根据公司具体业务需求开发的,不一定符合每个人的要求
  2. 该组件只是提供一个思路,可在此拓展更复杂的业务场景

http://www.ppmy.cn/devtools/10282.html

相关文章

【MySQL 数据宝典】【磁盘结构】- 005 Undo log 撤销日志

一、基本介绍 ​ 每当我们要对一条记录做改动时&#xff08;这里的改动可以指 INSERT 、 DELETE 、 UPDATE &#xff09;&#xff0c;都需要留一手 -> 把回滚时所需的东西都给记下来 ​ 你插入一条记录时&#xff0c;至少要把这条记录的主键值记下来&#xff0c;之后回滚的…

处理游戏提示找不到steam_api64.dll丢失的方法

steam_api64.dll 是一个专门为 64 位 Windows 操作系统设计的动态链接库&#xff08;Dynamic Link Library&#xff0c;简称 DLL&#xff09;文件&#xff0c;与 steam_api.dll 类似&#xff0c;但针对的是 64 位应用程序。它属于 Steam 平台的一部分&#xff0c;主要服务于通过…

在ubuntu20上编译bcc时遇到:Could NOT find LibDebuginfod

参考&#xff1a;https://github.com/iovisor/bcc/issues/3601 安装clang-12&#xff1a; wget https://apt.llvm.org/llvm.sh chmod x llvm.sh ./llvm.sh 12 al创建软连接&#xff1a; /usr/bin# ln -sf clang-12 clang /usr/bin# ln -sf clang-12 clang /usr/bin# ln -sf …

2024-04-22-医学图像IXI数据集处理

摘自&#xff1a;2023-CIBM-Multi-Stage Hybrid Attention Network for MRI reconstruction and SR By applying k-space truncation degradation and masks sequentially, we synthesize various LR under-sampled MR images, where we fully sample along the frequency-enc…

React 19 带来了 JSX 运行时的重要更新

在 React 的发展历程中&#xff0c;JSX 运行时一直扮演着重要的角色。在以前的的版本&#xff0c;JSX 运行时会克隆传入的 props 对象&#xff0c;这背后有着两大原因。 历史原因 React 保留了一些特殊的 prop 名称&#xff0c;如 key 和在 React 19 之前的 ref。这些 prop 并…

uniapp微信小程序分包

一、创建分包文件夹subPack 二、将页面文件放入分包文件夹中 启动页面和导航tabBar页面不要放入分包文件夹中 三、配置pages.json 四、效果

Dubbo SPI 和 Java SPI 区别

JDK SPI JDK 标准的 SPI 会一次性加载所有的扩展实现&#xff0c;如果有的扩展吃实话很耗时&#xff0c;但也没用上&#xff0c;很浪费资源。所以只希望加载某个的实现&#xff0c;就不现实了 DUBBO SPI 1&#xff1a; 对 Dubbo 进行扩展&#xff0c;不需要改动 Dubbo 的源码 …

Linux:安装及管理程序

Linux&#xff1a;安装及管理程序 应用程序基础 应用程序与系统命令的关系 角色系统命令应用程序文件位置般在/bin和/sbin目录中&#xff0c;或为Shell内部指令通常在/usr/bin、/usr/sbin 和/usr/local/bin、/usr/local/sbin目录中主要用途完成对系统的基本管理工作&#xf…