我如何在 React 中制作一个只允许数字或空值的文本框,这会触发移动设备上的数字键盘?
How can I make a text box in React which allows only numbers or an empty value, which triggers the number keypad on mobile?
在 Whosebug 上有很多这样的问题,但其中 none 在同一个解决方案中捕获了我的所有需求。任何帮助表示赞赏。
问题
在我的 React 应用中,我需要一个具有以下特征的文本框:
- 它只允许输入数字 - 除了数字 0-9 之外,不允许输入减号、小数位、字母或任何其他内容。
- 它会自动在 iOS 和 Android
上调出数字键盘
- 我可以进一步限制应该输入的数字,例如只允许 4 位数字
- 前导零自动 trimmed,例如如果用户输入 02 它应该更正为 2
- 它允许空文本框,并且可以区分空值和 0
当前代码
https://codepen.io/micahrl/pen/RwGeLmo
此代码允许输入非数字,并且只会将值解释为 NaN。例如,用户可以键入 2f
或 asdf
,页面将显示 You typed: NaN
.
此外,虽然页面最初加载时带有一个空文本框,但用户无法键入内容然后将其删除回空。尝试删除输入框中的所有文本会在框中放置一个 0
。
最后,此代码不能可靠地 trim 前导零,这给我带来了特殊问题,因为我想将数字限制为四位数。输入 01
不会截断前导零;在某些浏览器上,键入 01111
将导致 1111
,这已经足够了,而在其他浏览器上,键入 01111
将导致 0111
,这是一个问题。
我试过的
因为我在input元素上设置了type="number"
,如果文本框里加了一个非数字,setNumWrapper
中的event.target.value
就会是一个空字符串。这意味着我无法区分真正的空字符串(用户已删除所有文本)和无效输入(用户键入了非数字,如 asdf
)。
我可以在输入元素上设置 type="text"
,除了我认为我需要将它设置为 number
才能在 iOS 和 [= 等移动操作系统上获得数字键盘60=].
通过进一步的实验以及@Keith 在评论中的一些帮助,我几乎解决了所有问题。
我已经在我的问题中分叉了 codepen,并在分叉中做了这些更改:https://codepen.io/micahrl/pen/GRjwqdO。
检查输入有效性
@Keith 向我指出 validity.badInput
(https://developer.mozilla.org/en-US/docs/Web/API/ValidityState/badInput)。有了这个,我可以区分空输入(用户键入内容然后删除它)和错误输入(用户尝试添加非数字字符)。
这意味着我将其添加到 setNumWrapper()
:
的开头
if (event.target.value === "") {
if (event.target.validity.badInput) {
// Set the text box and number to the old value - ignore the bad input
inputRef.current.value = String(num);
setNum(num);
} else {
// The data in the text box was deleted - set everything to empty
inputRef.current.value = "";
setNum(NaN);
}
return;
}
我还必须用 useRef()
制作一个 inputRef
,并将其设置在 <input>
元素上。
这解决了 #1 中的大部分问题(但请参阅下面的剩余小问题)。
修剪前导零
为此,我所要做的就是使用 inputRef
在 setNumWrapper()
末尾的 <input>
元素中设置值:
inputRef.current.value = String(newNum);
无论如何,<input>
元素的值始终是一个字符串,并且将数字强制转换为字符串并删除前导零(如果有的话)。
遗留问题:如果文本框为空,则允许无效输入
当文本框为空时,用户可以在其中输入非数字字符,setNumWrapper()
甚至不会触发。如果将 console.log()
放在 setNumWrapper()
的顶部,如果用户键入字母,它不会在日志中打印任何内容,但如果用户键入数字,它会在日志中打印。
这意味着我无法使用setNumWrapper()
来解决这个问题。
然而,它也相对较小。在手机上,数字键盘出现,防止非数字输入。在桌面上,没有什么可以阻止用户使用键盘输入字母,但对于我的应用程序,很明显只允许使用数字,所以现在这已经足够了。
不过,如果有办法解决这个问题,我很想听听。
在 Whosebug 上有很多这样的问题,但其中 none 在同一个解决方案中捕获了我的所有需求。任何帮助表示赞赏。
问题
在我的 React 应用中,我需要一个具有以下特征的文本框:
- 它只允许输入数字 - 除了数字 0-9 之外,不允许输入减号、小数位、字母或任何其他内容。
- 它会自动在 iOS 和 Android 上调出数字键盘
- 我可以进一步限制应该输入的数字,例如只允许 4 位数字
- 前导零自动 trimmed,例如如果用户输入 02 它应该更正为 2
- 它允许空文本框,并且可以区分空值和 0
当前代码
https://codepen.io/micahrl/pen/RwGeLmo
此代码允许输入非数字,并且只会将值解释为 NaN。例如,用户可以键入 2f
或 asdf
,页面将显示 You typed: NaN
.
此外,虽然页面最初加载时带有一个空文本框,但用户无法键入内容然后将其删除回空。尝试删除输入框中的所有文本会在框中放置一个 0
。
最后,此代码不能可靠地 trim 前导零,这给我带来了特殊问题,因为我想将数字限制为四位数。输入 01
不会截断前导零;在某些浏览器上,键入 01111
将导致 1111
,这已经足够了,而在其他浏览器上,键入 01111
将导致 0111
,这是一个问题。
我试过的
因为我在input元素上设置了type="number"
,如果文本框里加了一个非数字,setNumWrapper
中的event.target.value
就会是一个空字符串。这意味着我无法区分真正的空字符串(用户已删除所有文本)和无效输入(用户键入了非数字,如 asdf
)。
我可以在输入元素上设置 type="text"
,除了我认为我需要将它设置为 number
才能在 iOS 和 [= 等移动操作系统上获得数字键盘60=].
通过进一步的实验以及@Keith 在评论中的一些帮助,我几乎解决了所有问题。
我已经在我的问题中分叉了 codepen,并在分叉中做了这些更改:https://codepen.io/micahrl/pen/GRjwqdO。
检查输入有效性
@Keith 向我指出 validity.badInput
(https://developer.mozilla.org/en-US/docs/Web/API/ValidityState/badInput)。有了这个,我可以区分空输入(用户键入内容然后删除它)和错误输入(用户尝试添加非数字字符)。
这意味着我将其添加到 setNumWrapper()
:
if (event.target.value === "") {
if (event.target.validity.badInput) {
// Set the text box and number to the old value - ignore the bad input
inputRef.current.value = String(num);
setNum(num);
} else {
// The data in the text box was deleted - set everything to empty
inputRef.current.value = "";
setNum(NaN);
}
return;
}
我还必须用 useRef()
制作一个 inputRef
,并将其设置在 <input>
元素上。
这解决了 #1 中的大部分问题(但请参阅下面的剩余小问题)。
修剪前导零
为此,我所要做的就是使用 inputRef
在 setNumWrapper()
末尾的 <input>
元素中设置值:
inputRef.current.value = String(newNum);
无论如何,<input>
元素的值始终是一个字符串,并且将数字强制转换为字符串并删除前导零(如果有的话)。
遗留问题:如果文本框为空,则允许无效输入
当文本框为空时,用户可以在其中输入非数字字符,setNumWrapper()
甚至不会触发。如果将 console.log()
放在 setNumWrapper()
的顶部,如果用户键入字母,它不会在日志中打印任何内容,但如果用户键入数字,它会在日志中打印。
这意味着我无法使用setNumWrapper()
来解决这个问题。
然而,它也相对较小。在手机上,数字键盘出现,防止非数字输入。在桌面上,没有什么可以阻止用户使用键盘输入字母,但对于我的应用程序,很明显只允许使用数字,所以现在这已经足够了。
不过,如果有办法解决这个问题,我很想听听。