浏览器原生的 input 标签支持传入 type 为 number 来限制只能输入数值,但这很多时候往往不是我们想要的,比如原始的 ui 中丑陋且在不同浏览器表现不一致的上下加减操作等,因此我们会有通过普通 input 创建数值型输入框的需求。
需求
自行书写数值型输入框的话,总担心自己会不会考虑不周,导致不满足需求,偶然间看到一个不错的例子。总结需要考虑的点有
- 只有在用户输入空格或负号以及正确的数值时,才响应用户的输入,否则不响应,这样就限制了用户的非法输入
- 失去焦点时,进行错误修正
- 如果以 . 结尾,或只有一个 -,则移除
- 去除首部多余的 0
示例
具体代码如下
/**
* @description 格式化成标准数字字符串(整数部分每三个进行分割)
* @param {*} value
*/
function formatNumber(value) {
value += "";
const list = value.split(".");
// 针对负数进行前缀提取
const prefix = list[0].charAt(0) === "-" ? "-" : "";
// 提取整数部分,没三位添加分隔符
let num = prefix ? list[0].slice(1) : list[0];
let result = "";
while (num.length > 3) {
result = `,${num.slice(-3)}${result}`;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return `${prefix}${result}${list[1] ? `.${list[1]}` : ""}`;
}
class NumericInput extends React.Component {
onChange = (e) => {
const { value } = e.target;
const reg = /^-?\d*(\.\d*)?$/;
// 如果是一个数,或者为空串或仅有一个 -,则触发事件
if ((!isNaN(value) && reg.test(value)) || value === "" || value === "-") {
this.props.onChange(value);
}
};
// '.' at the end or only '-' in the input box.
onBlur = () => {
const { value, onBlur, onChange } = this.props;
let valueTemp = value;
// 如果以 . 结尾,或只有一个 -,则在失焦时移除
if (value.charAt(value.length - 1) === "." || value === "-") {
valueTemp = value.slice(0, -1);
}
// 去除首部多余的 0
onChange(valueTemp.replace(/0*(\d+)/, "$1"));
if (onBlur) {
onBlur();
}
};
render() {
const { value } = this.props;
const title = value ? (
<span className="numeric-input-title">
{value !== "-" ? formatNumber(value) : "-"}
</span>
) : (
"Input a number"
);
return (
<Tooltip
trigger={["focus"]}
title={title}
placement="topLeft"
overlayClassName="numeric-input"
>
<Input
{...this.props}
suffix="m"
onChange={this.onChange}
onBlur={this.onBlur}
placeholder="Input a number"
maxLength={25}
/>
</Tooltip>
);
}
}