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

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

需求原型

在这里插入图片描述

使用场景

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

实现思路

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

代码结构

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

/*
 * @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; // 分割线和数据框的 gap
  placeholder: [string, string]; // 占位符
  suffix: string; // 后缀,不传则不显示
} & InputNumberProps

const 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.Item
              name="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 分隔符间距 number 15 -
placeholder 占位符 [string,string] [‘最小值’, ‘最大值’] -
precision 数值精度 number 2 -
min 最小值 number 0 -
max 最大值 number 99999999.99 -
suffix 后缀 string - -

除此之外支持所有 InputNumber属性

效果预览

在这里插入图片描述

注意事项

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

相关推荐

  1. 基于antdesign封装一个react上传组件

    2024-04-23 00:32:03       35 阅读
  2. React】使用 antd 加载组件实现 iframe 加载效果

    2024-04-23 00:32:03       26 阅读
  3. react基于antd二次封装分页组件Pagination

    2024-04-23 00:32:03       63 阅读
  4. react hooks antd组件取子组件form表单

    2024-04-23 00:32:03       25 阅读
  5. antd react 上传组件 customRequest 讲解

    2024-04-23 00:32:03       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-23 00:32:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-23 00:32:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-23 00:32:03       82 阅读
  4. Python语言-面向对象

    2024-04-23 00:32:03       91 阅读

热门阅读

  1. Qt Creator 调试控制台无法查看 log4z 的日志

    2024-04-23 00:32:03       29 阅读
  2. 解决Valid在@RequestParam场景不生效的问题

    2024-04-23 00:32:03       39 阅读
  3. C语言例题(递归、二分查找、冒泡排序)

    2024-04-23 00:32:03       36 阅读
  4. 在nginx配置中返回文本

    2024-04-23 00:32:03       36 阅读
  5. 年轻人选择程序员岗位往往都有哪些原因

    2024-04-23 00:32:03       27 阅读
  6. 若依框架升级SpringBoot3

    2024-04-23 00:32:03       38 阅读
  7. 设计模式|组合模式(Composite Pattern)

    2024-04-23 00:32:03       35 阅读
  8. mybatis使用xml中的if-else/choose

    2024-04-23 00:32:03       34 阅读
  9. c#程序调用c++开发dll库

    2024-04-23 00:32:03       30 阅读