antd 的 InputNumber 输入框添加左右的加减按钮

蚊子前端博客
发布于 2023-10-17 23:12
我们来封装一个有左右切换按钮的数字输入框

antd 现在提供的 <InputNumber /> 组件只能点击输入内的上下键来修改数值,不过我希望得到下图中的组件:

有左右加减按钮的数字输入框-蚊子的前端博客

我们这里来封装下。封装时要注意的几点:

  1. 能全部接收<InputNumber />所有的参数;

  2. 当数字达到上下限时,需将按钮置灰;

  3. 隐藏<InputNumber />本身内置的上下切换键;

  4. 点击左右按钮时,能实时调整数值;

1. 接收内置的所有参数

我们可以直接使用 antd 中内置的类型来扩展我们组件的类型:

COPYJAVASCRIPT

import type { InputNumberProps } from "antd"; interface NumUpDownProps extends InputNumberProps { className?: string; } const NumberUpDown = (props: NumUpDownProps) => {}; export default NumberUpDown;

我们在原类型的基础上又扩展了出了自己的字段。

2. 数字达到上下限时,将按钮置灰

假如设置了输入框中数字的上下限,我们就得需要判断当前数值是否达到了下限或者上限,若达到了,则将其中一侧的按钮置灰。

COPYJAVASCRIPT

import React, { useMemo } from "react"; const NumberUpDown = (props: NumUpDownProps) => { const { minDisabled, maxDisabled } = useMemo(() => { const min = props.min ?? Number.MIN_SAFE_INTEGER; const max = props.max ?? Number.MAX_SAFE_INTEGER; const minDisabled = typeof props.value === "number" ? props.value <= min : false; const maxDisabled = typeof props.value === "number" ? props.value >= max : false; return { minDisabled, maxDisabled }; }, [props.value, props.min, props.max]); };

若没有设置上下限,我们就认为是无限大和无限小,方便我们统一地判断。

3. 隐藏组件内置的上下切换键

<InputNumber />的属性中,没有可以隐藏上下切换键的属性,我们可以从 CSS 层面,将其隐藏。

COPYCSS

.ant-input-number { border-top: none; border-bottom: none; border-radius: 0; .ant-input-number-input { padding: 0; text-align: center; height: 32px; } .ant-input-number-handler-wrap { display: none; } }

上面代码中的display: none就是用来隐藏切换键的。

4. 点击左右按钮,可实时调整数值

按钮的行为只有两种:增加或者减少。

  1. 若没有初始值,则默认是 1;

  2. 若没有默认的调整步数 step,则默认是 1;

COPYJAVASCRIPT

const handleClick = (type: "plus" | "minus") => { const value = Number(props?.value || 0); const step = Number(props?.step || 1); const newValue = type === "plus" ? value + step : value - step; props?.onChange?.(newValue); };

将调整后的值回传回去。

5. 总结

整体来说,这个组件的封装并不是很难。在表单中调用时:

COPYJAVASCRIPT

<Form.Item name="num" label="上下限"> <NumberUpDown min={1} max={5} /> </Form.Item>

现将完整的代码公布一下。

5.1 React 代码

COPYJAVASCRIPT

import { Button, InputNumber } from "antd"; import type { InputNumberProps } from "antd"; import { MinusOutlined, PlusOutlined } from "@ant-design/icons"; import classNames from "classnames"; import React, { useMemo } from "react"; import "./number-up-down.less"; interface NumUpDownProps extends InputNumberProps { className?: string; } const NumberUpDown = (props: NumUpDownProps) => { const { minDisabled, maxDisabled } = useMemo(() => { const min = props.min ?? Number.MIN_SAFE_INTEGER; const max = props.max ?? Number.MAX_SAFE_INTEGER; const minDisabled = typeof props.value === "number" ? props.value <= min : false; const maxDisabled = typeof props.value === "number" ? props.value >= max : false; return { minDisabled, maxDisabled }; }, [props.value, props.min, props.max]); const handleClick = (type: "plus" | "minus") => { const value = Number(props?.value || 0); const step = Number(props?.step || 1); const newValue = type === "plus" ? value + step : value - step; props?.onChange?.(newValue); }; return ( <div className={classNames("number-up-down-field", props.className)}> <Button className="change-btn" icon={<MinusOutlined />} type="text" disabled={minDisabled} onClick={() => handleClick("minus")} ></Button> <InputNumber {...props} /> <Button className="change-btn" icon={<PlusOutlined />} type="text" disabled={maxDisabled} onClick={() => handleClick("plus")} ></Button> </div> ); }; export default NumberUpDown;

5.2 样式代码

COPYCSS

.number-up-down-field { display: flex; align-items: center; border: 1px solid #d9d9d9; border-radius: 2px; background-color: #ffffff; .change-btn { border-radius: 0; } .ant-input-number { border-top: none; border-bottom: none; border-radius: 0; .ant-input-number-input { padding: 0; text-align: center; height: 32px; } .ant-input-number-handler-wrap { display: none; } } }
标签:
阅读(347)

公众号:

qrcode

微信公众号:前端小茶馆