有没有办法防止 input type="number" 接收负数值?

448
我想要获取仅为正数的值,是否有仅使用HTML的方法来防止输入负数?
请不要建议验证方法。

输入控件的屏幕截图


5
这个帖子更详细地回答了同样的问题:https://dev59.com/9FwZ5IYBdhLWcg3wVfAC - PiotrWolkowski
那用户怎么办(而不是开发者)?如果我输入-3,我得到了一个3,这不是我想要的!完全没有意义!只需保留-3并给我一个解释错误。为什么大多数开发人员认为这种可怕的行为是用户友好的呢?当开发人员在不告诉我的情况下破坏我的键盘时,我很讨厌它。 - Cesar
18个回答

858

按照以下方式使用min属性

<input type="number" min="0">

7
这是一个更可靠的参考来源:(https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-min)。 - Álvaro González
368
这将阻止使用箭头按钮/微调器输入负数。但是,用户仍然可以手动输入负数,并使该字段的值作为负数读取,从而绕过最小属性限制。 - ecbrodie
90
没错。但这个回答只回答了问题的一半,为什么会得到这么多赞就是个谜了。 - GôTô
10
无效,用户仍可以手动输入负数。 - Altef four
5
我仍然可以将负数复制粘贴到输入字段中。我会寻找另一个解决方案。这个对我来说不完全可行。 - Ankit Vij
显示剩余8条评论

219

我找到的解决方案是:

<input type="number" min="0" oninput="this.value = Math.abs(this.value)">

编辑

根据评论中的建议进行了微小的更改,以使其在最小值为0的情况下仍能工作。

<input type="number" min="0" oninput="this.value = 
 !!this.value && Math.abs(this.value) >= 0 ? Math.abs(this.value) : null">


3
使用angular中的模式和noformvalidate是最好的解决方案,因为如果不在范围内,则模型不会更新。例如:<input ng-model="row.myValue" type="{{row.code == 1 ? 'text' : 'number'}}" min="0" ng-pattern="..." noformvalidate oninput="if (this.type=='text') this.value=Math.abs(this.value) "> - sebius
1
当用户知道默认值为0时,这是最好的解决方案。否则,用户在按退格键时会感到困惑,不清除字段的原因是什么。除此之外,这是最佳解决方案。+1 - Deep 3015
1
这个是最好的,而且在使用小数时也适用。我之前使用过其他答案,但当需要允许小数时它就停止工作了。我们能否将这个答案移到上面,以便大多数人都可以使用它呢? - Subhan Ahmed
2
如果你想在填写后保留空白(例如使用退格键),你应该使用这个 this.value = Math.abs(this.value) > 0 ? Math.abs(this.value) : null - ali6p
1
唯一有效的解决方案,没有负面输入,没有负面复制/粘贴,没有负面滚动。 - Bharat
显示剩余7条评论

158

我对@Abhrabm的回答不满意,因为:

它只能防止从上 / 下箭头输入负数,而用户可以通过键盘输入负数。

解决方法是使用按键代码来防止:

// Select your input element.
var number = document.getElementById('number');

// Listen for input event on numInput.
number.onkeydown = function(e) {
    if(!((e.keyCode > 95 && e.keyCode < 106)
      || (e.keyCode > 47 && e.keyCode < 58) 
      || e.keyCode == 8)) {
        return false;
    }
}
<form action="" method="post">
  <input type="number" id="number" min="0" />
  <input type="submit" value="Click me!"/>
</form>

@Hugh Guiney 提供的澄清:

正在检查哪些按键代码:

  • 95,<106 对应于小键盘0到9;
  • 47,<58 对应于数字行上的0到9;8 是退格键。

因此,该脚本防止无效的按键被输入。


25
赞同,但我认为有必要澄清正在检查哪些关键代码:> 95、< 106 对应于数字键盘上的0到9;> 47、< 58 对应于数字行上的0到9;而8代表的是退格键。因此,该脚本防止输入除这些按键以外的任何按键。它很全面,但我认为对于那些本地支持数字输入并已经过滤掉字母键(除了像“e”这样具有数字意义的字符之类的字符)的浏览器来说,这可能有些过头了。只需要防止189(破折号)和109(减号)。然后与min="0"结合使用可能就足够了。 - Hugh Guiney
3
@Manwal 它限制了使用键盘复制和粘贴数字。并允许我使用鼠标复制粘贴负数。 - Beniton Fernando
1
@Beniton 感谢您提供这个用例。您能给我一点关于您正在做什么的想法吗?我总是可以帮助您解决问题。请提供一些可运行的代码或 fiddle。您可以在代码中进行表单提交级别的验证。虽然如果我不允许负数,我总是会在后端进行检查。 - Manwal
1
基本上只需复制粘贴到字段中即可。这并不是什么特殊情况。与其通过按键代码处理验证,最好在onChange或focusOut上进行,并构建一个小的验证函数来捕获任何负数。 - ulisesrmzroche
3
需要添加箭头键(37、38、39、41)的条件语句。如下所示:|| (e.keyCode>36 && e.keyCode<41) 这将防止用户通过上下箭头键来增加或减少数字,并防止用户使用左右箭头键编辑数字。 - vusan
显示剩余6条评论

44

这段代码在我的环境中可以正常工作。你能否检查一下:

<input type="number" name="test" min="0" oninput="validity.valid||(value='');">

5
这种方法是可行的,但在尝试输入“-”后清空整个输入并不是一个好主意。 - extempl
15
听起来对于试图在一个常识表明不存在负数的字段中输入负数的用户来说,这是一种公平的惩罚。 - KhoPhi
4
<input type="number" name="test" min="0" oninput="validity.valid||(value=value.replace(/\D+/g, ''))"> - 这会删除所有非数字符号。 - Oleh Melnyk
1
你如何在React中实现这个? - Paul Razvan Berg
1
我尝试过这个方法,但它也阻止了输入带小数点的数字。 - Len
显示剩余3条评论

27

简单方法:

<input min='0' type="number" onkeypress="return (event.charCode == 8 || event.charCode == 0) ? null : event.charCode >= 48 && event.charCode <= 57">


4
简单易懂...但是,负数也可能被放置。 - Ralf
5
简洁明了,但无效。 - lmat - Reinstate Monica
1
"event.charCode"现在已经被弃用。 - SRJ

8

我希望允许输入小数,如果输入了负数,不会清除整个输入内容。至少在谷歌浏览器中可以正常工作:

<input type="number" min="0" onkeypress="return event.charCode != 45">

如何在此处添加更多的ASCII码?例如,我想添加46与45。应该如何实现? - Pradeep Singh
3
"return [45, 46].indexOf(event.charCode) == -1" 可以翻译为:返回值为"[45, 46]"中不包括输入事件的字符编码"event.charCode"时,返回结果为真。 - ykay says Reinstate Monica
请打破常规思维。您真的确定 keypress 是唯一的方式,可以在输入框中输入负数吗? - Roko C. Buljan

7

以下是Angular 2的解决方案:

创建一个名为OnlyNumber的类:

import {Directive, ElementRef, HostListener} from '@angular/core';

@Directive({
  selector: '[OnlyNumber]'
})
export class OnlyNumber {

  // Allow decimal numbers. The \. is only allowed once to occur
  private regex: RegExp = new RegExp(/^[0-9]+(\.[0-9]*){0,1}$/g);

  // Allow key codes for special events. Reflect :
  // Backspace, tab, end, home
  private specialKeys: Array<string> = ['Backspace', 'Tab', 'End', 'Home'];

  constructor(private el: ElementRef) {
  }

  @HostListener('keydown', ['$event'])
  onKeyDown(event: KeyboardEvent) {
    // Allow Backspace, tab, end, and home keys
    if (this.specialKeys.indexOf(event.key) !== -1) {
      return;
    }

    // Do not use event.keycode this is deprecated.
    // See: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
    let current: string = this.el.nativeElement.value;
    // We need this because the current value on the DOM element
    // is not yet updated with the value from this event
    let next: string = current.concat(event.key);
    if (next && !String(next).match(this.regex)) {
      event.preventDefault();
    }
  }
}

在 app.module.ts 中添加 OnlyNumber 到声明中,然后在应用程序的任何地方像这样使用它。
<input OnlyNumber="true">

有没有办法允许粘贴?另外,我将正则表达式更改为: /^-?[0-9]+(.[0-9]*){0,1}$/g 以允许负数,但好像不起作用? - Dave Nottage

7
@Manwal的回答很好,但为了更好地可读性,我喜欢用较少的代码行数编写代码。另外,我喜欢在html中使用onclick/onkeypress。

我的建议解决方案与@Manwal的相同: 添加

min="0" onkeypress="return isNumberKey(event)"

将其添加到HTML输入框中

function isNumberKey(evt){
    var charCode = (evt.which) ? evt.which : event.keyCode;
    return !(charCode > 31 && (charCode < 48 || charCode > 57));
}

作为一个JavaScript函数,它的功能与上述说法相同。只是在解决问题时有个人偏好而已。

5

仅供参考:使用jQuery,您可以通过以下代码在focusout时覆盖负值:

$(document).ready(function(){
    $("body").delegate('#myInputNumber', 'focusout', function(){
        if($(this).val() < 0){
            $(this).val('0');
        }
    });
});

这并不替代服务器端验证!


如果用户从输入字段中移开焦点,这将正常工作,但是如果他们在仍然在该字段中立即按下回车键,则仍然可以输入负数。 - NemyaNation

5

只需使用min="0"

<v-text-field
   v-model="abc"
   class="ml-1 rounded-0"
   outlined
   dense
   label="Number"
   type="number"
   min="0">
</v-text-field>


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