143

我正在构建主要用于移动浏览器的网络应用程序。我使用数字类型的输入字段,因此(大多数)移动浏览器仅调用数字键盘以获得更好的用户体验。这个网络应用程序主要用于小数点分隔符是逗号而不是点的区域,所以我需要处理两个小数点分隔符。

如何用点和逗号覆盖整个混乱?

我的发现:

桌面铬

  • 输入类型=数字
  • 用户输入“4,55”输入字段
  • $("#my_input").val();返回“455”
  • 我无法从输入中获得正确的值

桌面火狐

  • 输入类型=数字
  • 用户输入“4,55”输入字段
  • $("#my_input").val();返回“4,55”
  • 没关系,我可以用点替换逗号并获得正确的浮点数

安卓浏览器

  • 输入类型=数字
  • 用户输入“4,55”输入字段
  • 当输入失去焦点时,值被截断为“4”
  • 让用户感到困惑

视窗电话 8

  • 输入类型=数字
  • 用户输入“4,55”输入字段
  • $("#my_input").val();返回“4,55”
  • 没关系,我可以用点替换逗号并获得正确的浮点数

在这种情况下,当用户可能使用逗号或点作为小数点分隔符并且我想将 html 输入类型保留为数字以提供更好的用户体验时,有哪些“最佳实践”?

我可以将逗号“即时”转换为点,绑定键事件,它是否与数字输入一起使用?

编辑

目前我没有任何解决方案,如何从类型设置为数字的输入中获取浮点值(作为字符串或数字)。如果最终用户输入“4,55”,Chrome 总是返回“455”,Firefox 返回“4,55”,这很好。

同样令人讨厌的是,在 Android(经过测试的 4.2 模拟器)中,当我输入“4,55”以输入字段并将焦点更改为其他位置时,输入的数字会被截断为“4”。

4

10 回答 10

117

我认为上面的答案中缺少的是需要为step属性指定一个不同的值,它的默认值为1. 如果您希望输入的验证算法允许浮点值,请相应地指定一个步骤。

例如,我想要美元金额,所以我指定了如下步骤:

 <input type="number" name="price"
           pattern="[0-9]+([\.,][0-9]+)?" step="0.01"
            title="This should be a number with up to 2 decimal places.">

使用 jQuery 检索值并没有错,但是您会发现直接使用 DOM API 来获取元素的validity.valid属性很有用。

我在小数点上遇到了类似的问题,但我意识到存在问题的原因是 Twitter Bootstrap 添加到具有无效值的数字输入的样式。

这是一个小提琴,演示了添加step属性使其工作,并测试当前值是否有效:

TL;DR: 将 astep属性设置为浮点值,因为它默认为1.

注意:逗号对我无效,但我怀疑如果我将操作系统语言/区域设置设置为使用逗号作为小数分隔符的某个位置,它会起作用。*注中*:在 Ubuntu/Gnome 14.04 中,操作系统语言/键盘设置 *德语* 不是这种情况。

于 2013-05-21T21:50:52.483 回答
26

根据 w3.org,数字输入的属性被定义为浮点数。浮点数的语法似乎只接受点作为小数分隔符。

我在下面列出了一些可能对您有帮助的选项:

1.使用pattern属性

使用pattern属性,您可以以 HTML5 兼容的方式使用正则表达式指定允许的格式。在这里,您可以指定允许使用逗号字符并在模式失败时提供有用的反馈消息。

<input type="number" pattern="[0-9]+([,\.][0-9]+)?" name="my-num"
           title="The number input must start with a number and use either comma or a dot as a decimal character."/>

注意:跨浏览器支持变化很大。它可能是完整的、部分的或不存在的。

2. JavaScript 验证

您可以尝试将一个简单的回调绑定到例如onchange(和/或blur)事件,该事件将替换逗号或一起验证。

3.禁用浏览器验证##

第三,您可以尝试在数字输入上使用formnovalidate属性,以便一起禁用该字段的浏览器验证。

<input type="number" formnovalidate />

4.组合..?

<input type="number" pattern="[0-9]+([,\.][0-9]+)?" 
           name="my-num" formnovalidate
           title="The number input must start with a number and use either comma or a dot as a decimal character."/>
于 2013-03-08T22:07:08.927 回答
10

是否使用逗号或句点作为小数点分隔符完全取决于浏览器。浏览器根据操作系统或浏览器的语言环境做出决定,或者某些浏览器从网站中获取提示。我做了一个浏览器比较图表,展示了不同的浏览器支持如何处理不同的本地化方法。Safari 是唯一可以互换处理逗号和句点的浏览器。

基本上,您作为网络​​作者无法真正控制这一点。一些变通方法涉及使用两个带整数的输入字段。这允许每个用户按照您的期望输入数据。它不是特别性感,但它适用于所有用户。

于 2015-02-08T15:15:04.973 回答
7

使用valueAsNumber而不是.val().

输入 。值作为编号 [ = 值 ]

如果适用,返回一个表示表单控件值的数字;否则,返回 null。
可以设置,改变值。
如果控件既不是基于日期或时间的也不是数字的,则引发 INVALID_STATE_ERR 异常。

于 2013-03-08T21:55:25.627 回答
7

使用文本类型但强制显示数字键盘

<input value="12,4" type="text" inputmode="numeric" pattern="[-+]?[0-9]*[.,]?[0-9]+">

inputmode 标签是解决方案

于 2019-01-24T00:31:04.263 回答
4

我还没有找到完美的解决方案,但我能做的最好的就是使用 type="tel" 并禁用 html5 验证(formnovalidate):

<input name="txtTest" type="tel" value="1,200.00" formnovalidate="formnovalidate" />

如果用户输入逗号,它将在我尝试过的每个现代浏览器(最新的 FF、IE、edge、opera、chrome、safari 桌面、android chrome)中输出逗号。

主要问题是:

  • 移动用户将看到他们的手机键盘,它可能与数字键盘不同。
  • 更糟糕的是,电话键盘甚至可能没有逗号键。

对于我的用例,我只需要:

  • 用逗号显示初始值(firefox 将其剥离为 type=number)
  • 不会失败 html5 验证(如果有逗号)
  • 让字段与输入完全相同(可能带有逗号)

如果您有类似的要求,这应该适合您。

注意:我不喜欢对模式属性的支持。formnovalidate 似乎工作得更好。

于 2016-04-05T23:14:58.980 回答
1

显然浏览器仍然有问题(尽管 Chrome 和 Firefox Nightly 做得很好)。对于那些真正必须使用数字字段的人,我有一个 hacky 方法(可能是因为文本字段没有的小箭头)。

我的解决方案

keyup在表单输入中添加了一个事件处理程序,并跟踪状态并在它再次有效时设置该值。

纯 JS 片段 JSFIDDLE

var currentString = '';
var badState = false;
var lastCharacter = null;

document.getElementById("field").addEventListener("keyup",($event) => {
  if ($event.target.value && !$event.target.validity.badInput) {
          currentString = $event.target.value;
  } else if ($event.target.validity.badInput) {
    if (badState && lastCharacter && lastCharacter.match(/[\.,]/) && !isNaN(+$event.key)) {
      $event.target.value = ((+currentString) + (+$event.key / 10));
      badState = false;
    } else {
      badState = true;
    }
  }
  document.getElementById("number").textContent = $event.target.value;
  lastCharacter = $event.key;
});

document.getElementById("field").addEventListener("blur",($event) => {
	if (badState) {
    $event.target.value = (+currentString);
    badState = false;
		document.getElementById("number").textContent = $event.target.value;
  }
});
#result{
  padding: 10px;
  background-color: orange;
  font-size: 25px;
  width: 400px;
  margin-top: 10px;
  display: inline-block;
}

#field{
  padding: 5px;
  border-radius: 5px;
  border: 1px solid grey;
  width: 400px;
}
<input type="number" id="field" keyup="keyUpFunction" step="0.01" placeholder="Field for both comma separators">

<span id="result" >
 <span >Current value: </span>
 <span id="number"></span>
</span>

Angular 9 片段

@Directive({
  selector: '[appFloatHelper]'
})
export class FloatHelperDirective {
  private currentString = '';
  private badState = false;
  private lastCharacter: string = null;

  @HostListener("blur", ['$event']) onBlur(event) {
    if (this.badState) {
      this.model.update.emit((+this.currentString));
      this.badState = false;
    }
  }

  constructor(private renderer: Renderer2, private el: ElementRef, private change: ChangeDetectorRef, private zone: NgZone, private model: NgModel) {
    this.renderer.listen(this.el.nativeElement, 'keyup', (e: KeyboardEvent) => {
      if (el.nativeElement.value && !el.nativeElement.validity.badInput) {
        this.currentString = el.nativeElement.value;
      } else if (el.nativeElement.validity.badInput) {
        if (this.badState && this.lastCharacter && this.lastCharacter.match(/[\.,]/) && !isNaN(+e.key)) {
          model.update.emit((+this.currentString) + (+e.key / 10));
          el.nativeElement.value = (+this.currentString) + (+e.key / 10);
          this.badState = false;
        } else {
          this.badState = true;
        }
      }       
      this.lastCharacter = e.key;
    });
  }
  
}
<input type="number" matInput placeholder="Field for both comma separators" appFloatHelper [(ngModel)]="numberModel">

于 2020-03-31T11:46:13.033 回答
1

当您调用$("#my_input").val();它时,它会作为字符串变量返回。所以使用parseFloatandparseInt进行转换。当您使用parseFloat桌面或手机时, ITSELF会理解变量的含义。

另外,您可以使用toFixedwhich 将浮点数转换为字符串,其参数为位数,如下所示:

var i = 0.011;
var ss = i.toFixed(2); //It returns 0.01
于 2015-12-17T08:53:29.427 回答
0

我的推荐?根本不要使用 jQuery。我和你有同样的问题。我发现$('#my_input').val()总是返回一些奇怪的结果。

尝试使用document.getElementById('my_input').valueAsNumber代替$("#my_input").val();然后,使用Number(your_value_retrieved)来尝试创建一个数字。如果值为 NaN,您肯定知道这不是一个数字。

要添加的一件事是,当您在输入上写一个数字时,输入实际上将接受几乎任何字符(我可以写欧元符号、美元和所有其他特殊字符),因此最好使用检索值.valueAsNumber而不是使用 jQuery。

哦,顺便说一句,这允许您的用户添加国际化(即:支持逗号而不是点来创建十进制数字)。只要让Number()对象为您创建一些东西,它就会是十进制安全的,可以这么说。

于 2013-04-04T21:33:02.950 回答
0

听起来您想在数字输入上使用 toLocaleString() 。

有关其用法,请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString

JS 中数字的本地化也包含在Internationalization(Number formatting "num.toLocaleString()") not working for chrome

于 2013-05-30T09:21:38.013 回答