防止在输入类型为数字的输入框中输入非数字字符

90

使用 <input type=number> 会导致在事件侦听器中,如果输入不是有效数字,则 this.value 返回空字符串。您可以在 http://jsfiddle.net/fSy53/ 查看示例。

但是,无效的字符仍然显示在输入框中。

有没有办法从事件侦听器内获取实际显示的值,包括无效字符?

我的最终目标是防止用户在字段中键入任何非数字字符。我需要使用 type=number,以便移动设备使用数字虚拟键盘。我的目标是在keyup keypress 上执行像 this.value = this.value.replace(/[^0-9.]/g, "") 这样的操作,但是这不起作用,因为如果键入无效字符,则从 this.value 读取将返回 ""


2
我觉得这之前已经有人问过了,答案是否定的,让我找找看。编辑:在这里:https://dev59.com/7HA75IYBdhLWcg3w0cjx - Qantas 94 Heavy
关于数字键盘:有一个新的HTML5属性inputmode,可以设置为numeric以显示数字键盘。不幸的是,根据mozilla,目前没有浏览器支持它。 - some
请注意,所描述的问题发生在Firefox中,但在Chrome中不会出现。如果设置了type='number',Chrome将防止非数字字符出现在输入框中。 - Sean the Bean
关于 inputmode 属性的更新:目前默认情况下没有任何浏览器支持它(请参见 http://caniuse.com/#search=inputmode),但可以通过设置 Firefox 的 dom.forms.inputmode 标志来启用它。 - Sean the Bean
1
防止用户输入非数字字符(即破坏他们的键盘)并不是很用户友好的做法。一个用户友好的方法是允许他们输入并解释出错的原因。试图将字符串输入到数字输入中的用户将不会理解为什么他的键盘停止工作了。我很惊讶有多少开发人员努力实现这种反用户功能。这适用于所有阻塞行为(最大长度、模式),非常不用户友好。更不用说用户通常在输入时不会看屏幕了。 - Cesar
显示剩余3条评论
16个回答

92

如果您不喜欢接收到的键值,请尝试阻止默认行为:

document.querySelector("input").addEventListener("keypress", function (evt) {
    if (evt.which < 48 || evt.which > 57)
    {
        evt.preventDefault();
    }
});

8
不正确。keypress事件在输入元素上触发,然后向文档冒泡传递。 - Glenn Lane
1
@megawac你有这方面的引用吗?那与我的经验相反。OP表示防止非数字内容是目标,我认为这是正确的方法:在其发生之前预防它,不必担心.value。 - Mike Edwards
1
@GlennLane 问题在于对于像$这样的Shift键,.which与非Shift键相同,并且在虚拟键盘上,e.shiftKey的值不会被设置为真值。相关链接:https://dev59.com/gXnZa4cB1Zd3GeqPlxvp - Explosion Pills
我在我的浏览器上没有发现这种行为... $ -> 36,4 -> 52。一定是Chrome的问题。 - Glenn Lane
5
这样做会导致你无法按方向箭头、退格键等,有一个更完整的解决方案可以参考:https://dev59.com/eHNA5IYBdhLWcg3wWseK#995193 - azhidkov
显示剩余8条评论

26

您可以通过阻止非数字值的keyPress事件来实现此操作。

例如(使用jQuery)

$('.input-selector').on('keypress', function(e){
  return e.metaKey || // cmd/ctrl
    e.which <= 0 || // arrow keys
    e.which == 8 || // delete key
    /[0-9]/.test(String.fromCharCode(e.which)); // numbers
})

这包括所有不同类型的输入(例如来自数字键盘的输入与来自键盘的输入具有不同的代码),以及退格键、方向键、控制/cmd + r重新加载等。


1
箭头键代码为37到40。https://dev59.com/aWEi5IYBdhLWcg3w4Pnr - Doug English
如果需要使用浮点数,可以将e.which == 46用于小数点键。 - Rene Limon
请注意,还有其他方法可以插入到HTML输入框中,例如复制粘贴、拖放和自动填充等。 - Yasser CHENIK

18
请注意,e.whiche.keyCodee.charCode已被弃用:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which 我更喜欢e.key:
document.querySelector("input").addEventListener("keypress", function (e) {
    var allowedChars = '0123456789.';
    function contains(stringValue, charValue) {
        return stringValue.indexOf(charValue) > -1;
    }
    var invalidKey = e.key.length === 1 && !contains(allowedChars, e.key)
            || e.key === '.' && contains(e.target.value, '.');
    invalidKey && e.preventDefault();});

通过检查字符串长度e.key.length === 1,此函数不会干扰Firefox(例如BackspaceTab等)中的控制代码。

它还可以防止在数字之间和开头出现重复的圆点:e.key === '.' && contains(e.target.value, '.')

不幸的是,它不能防止末尾的多个点:234....

看起来没有办法解决这个问题。


2
我喜欢这种方法。它很干净,而且运行良好。唯一的问题是它会阻止像Ctrl+R(重新加载当前页面),Ctrl+A等操作。我认为可以安全地添加一个!e.ctrlKey检查。 - mfulton26
1
keypress事件也已被弃用。请参见https://developer.mozilla.org/en-US/docs/Web/API/Document/keypress_event和https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event。 - Raikish

8

其他答案看起来比必要的复杂,所以我将他们的答案调整为这个简短而甜美的函数。

function allowOnlyNumbers(event) {
  if (event.key.length === 1 && /\D/.test(event.key)) {
    event.preventDefault();
  }
}

这不会改变任何箭头、回车、Shift、Ctrl或Tab键的行为,因为这些事件的键属性长度超过一个字符。它还使用简单的正则表达式来查找任何非数字字符。


那么如果有人想要十进制数呢?比如 10.01?而且这也不会阻止 1.1.1 的提交。 - GeorgeWL
按下CTRL + X无法使用此功能。 - D-rk
if条件中添加!e.shiftKey && !e.ctrlKey && !e.metaKey && - tony19

4
这个解决方案对我来说似乎很有效。它基于 @pavok 的解决方案,并保留了 ctrl 键命令。
document.querySelector("input").addEventListener("keypress", function (e) {
  if (
    e.key.length === 1 && e.key !== '.' && isNaN(e.key) && !e.ctrlKey || 
    e.key === '.' && e.target.value.toString().indexOf('.') > -1
  ) {
    e.preventDefault();
  }
});

迄今为止最佳解决方案 - undefined

3
inputs[5].addEventListener('keydown', enterNumbers);

function enterNumbers(event) {
  if ((event.code == 'ArrowLeft') || (event.code == 'ArrowRight') ||
     (event.code == 'ArrowUp') || (event.code == 'ArrowDown') || 
     (event.code == 'Delete') || (event.code == 'Backspace')) {
     return;
  } else if (event.key.search(/\d/) == -1) {
    event.preventDefault();
  }
}

在这种情况下,当按下非数字按钮时,输入框中的值保持不变,同时删除、回退、箭头上下左右键仍能正常使用并可用于修改数字输入。

2
尝试这个:
  1. 当前按下的键 -> e
  2. 如果 e 不是一个数字 -> isNaN(e.key)
  3. 当条件为真时,不能像通常那样执行默认操作 -> e.preventDefault()
  4. 否则,返回默认操作... e
input.addEventListener("keypress", function (e) {
  if (isNaN(e.key)) e.preventDefault();
});

请问您能否解释一下您的代码是如何解决OP的问题的?并且能否说明一下它的作用? - Alexander
任何按键按下都等于(e)参数,如果e.key不是数字,则返回preventDefault(),那么preventDefault()方法是什么?...告诉用户代理,如果事件没有明确处理,那么它的默认操作不应像通常那样被执行。 - farid teymouri
谢谢您的回复,但我希望您能编辑您的答案并提供这些详细信息,以提高您的帖子质量。您会注意到,当用户用“尝试这个”和几行代码回答问题时,答案很少表现良好。 - Alexander
对不起,你是正确的。 - farid teymouri

1

我也会添加MetaKey,因为我正在使用MacOS

input.addEventListener("keypress", (e) => {
    const key = e.key;
    if (!(e.metaKey || e.ctrlKey) && key.length === 1 && !/\d\./.test(key)) {
        e.preventDefault();
    }
}

或者,您可以尝试 !isNaN(parseFloat(key))

1

接受答案的更新:

由于许多属性变得过时

(属性) KeyboardEvent.which: 数字 @过时

你应该只依赖key属性,并自己创建其余逻辑:

该代码允许Enter、Backspace和所有数字[0-9],其他任何字符都被禁止。

document.querySelector("input").addEventListener("keypress", ({ key, preventDefault }) => {
  if (isNaN(parseInt(key, 10)) && !['Backspace', 'Enter'].includes(key)) {
      preventDefault();
    }
});

注意 这将禁用粘贴操作


0

这是我的简单解决方案,您只需将输入类型保持为文本,这样当您使用event.target.value时,您将获得完整的字符串,而不仅仅是数字或空字符串,因此您实际上可以检查是否已经有一个点或者没有。我没有使用已弃用的属性event.which

isNumber(event) {
      var allowed = "";
      if (event.target.value.includes(".")) {
        allowed = "123456789";
      } else {
        allowed = "123456789.";
      }
      if (!allowed.includes(event.key)) {
        event.preventDefault();
      }
    }

document.getElementById('number').addEventListener('keypress', isNumber);

the HTML 


```

 function isNumber(event) {
      var allowed = "";
      if (event.target.value.includes(".")) {
        allowed = "0123456789";
      } else {
        allowed = "0123456789.";
      }
      if (!allowed.includes(event.key)) {
        event.preventDefault();
      }
      }
      
      document.getElementById('number').addEventListener('keypress',isNumber);
<h3>You can input only numbers and one point (this would be a float or int) </h3>
<input type="text" id="number" />


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接