为什么这个输入是有效的?

18

在这种情况下,为什么我的数字输入使用input.validity.valid返回值0.的有效性为真?

<input type="number" min="1" max="999" step="1" value="0." id="one" /> <!--Valid??-->
<input type="number" min="1" max="999" step="1" value="0.0" id="two" /> <!--fine-->
<input type="number" min="1" max="999" step="1" value="0" id="three" /> <!--fine-->

Chrome 37.0.2062.103 m

jsFiddle

Edit:

奇怪的是,任何以句号结尾的负数也会破坏验证。

<input type="number" min="1" max="999" step="1" value="-14." id="one" />

jsFiddle


你可以添加一个明确的“pattern”属性。 - vsync
@vsync 我无法为数字输入添加pattern属性 - 它会被忽略 - CodingIntrigue
2
你的个人头像很适合你的情况 :) - sabithpocker
2
被删除的答案在评论中有一个有用的小工具,可以用于测试。特别是因为当您从程序中设置事物时,与您将它们键入输入时会得到不同的结果。不确定是谁创建了它,但它在这里http://jsfiddle.net/8pucueqr/。 - CupawnTae
4个回答

7
注意:自本答案撰写以来,#1中提到的Chrome错误已经修复,因此现在仅适用于#2。
实际上有两个答案:
1. Chrome 中存在一个错误,这意味着当您在输入字段中输入/设置类似于 0. 的值时,无法正确验证。 2. 如果在 HTML 标记中设置无效值,则浏览器需要忽略它并将该值设置为空字符串,除非该字段标记为“required”,否则该值被视为有效。
严格来说,正是第一个原因导致了您所看到的行为,因为它阻止了#2的发生,但如果在 Chrome 中修复了该错误,则只需处理初始标记(而不是任何后续用户交互),#2 将适用。
还值得注意的是,#2 是导致 Firefox 中类似(但不完全相同)行为的原因。

1. Chrome 错误

rangeUnderflow 使用 Decimal::fromString(...),如果输入以 . 结尾,则返回 NaN,导致 rangeUnderflow 返回 false

if (!numericValue.isFinite())
   return false;

相反,badInput 使用 StringToDoubleConverter::StringToDouble(...),它基本上忽略了一个尾随的 .,所以输入不被视为“坏的”。
根据 规范
一个字符串是一个有效的浮点数,如果它包含以下内容:
  1. 可选的,一个U+002D连字符字符(-)。
  2. 以下一项或两项中的一项,按给定顺序:
  3. 一个或多个ASCII数字的系列。
    1. 一个单独的U+002E句点字符(.)。
    2. 一个或多个ASCII数字的系列。
请注意,2.2.2不是可选的 - 也就是说,如果你有一个.,你必须在它后面加上数字。
所以错误的是badInput。(如果Chrome至少对待0.作为有效的是一致的,那么就会检测到rangeUnderflow
2.标记与用户输入
例如,如果在HTML中设置value="aaa"。即使aaa会导致badInputtrue,输入仍将显示为有效。
这是因为在解析/渲染页面时,Chrome会对属性值运行一个值净化算法。当它看到一个不是有效的浮点数的值时,必须按规范要求将输入的值设置为空字符串。除非输入被标记为required,否则空字符串被认为是有效的。目前,在Chrome中对于value="0.",它(错误地)通过了值净化算法,因此不会发生这种情况。但是,如果/当他们在Chrome中修复了这个错误,这就是你所期望发生的事情。
如果您在输入框中实际键入aaa,则它将显示为无效,即badInput===true。同样,在Firefox中以及在Chrome中(如果/当他们修复了此错误),如果您在字段中键入0.,它将给出badInput===true,因此valid===false

3
规范中写道:

用户代理不能允许用户将值设置为非空字符串,而该字符串不是有效的浮点数。 如果用户代理提供了用于选择数字的用户界面,则必须将该值设置为表示用户选择的最佳浮点数字的数字表示。

规范继续说道:

价值净化算法如下:如果元素的值不是有效的浮点数,则将其设置为空字符串。

在Firefox中,DOM中的value被设置为空字符串,这是一个有效的状态。如果您想使第一个字段在这种情况下无效,您必须将其设置为required
<input type="number" min="1" max="999" step="1" value="0." id="one" required />

规范也指出:

约束验证:当用户界面描述输入时,用户代理无法将其转换为有效的浮点数时,控件会遭受错误的输入。

我认为在这种情况下 Firefox (32.0)的操作是正确的,只要 #one 输入框未显示 0. 值。在 Firefox 中,如果我手动在 #one 输入框中键入值 0.,则会被正确地标记为无效。

然而,在 Chrome 38.0.2125.58 beta-m 中,即使 document.querySelector(“#one”).value 求值为空字符串,0. 值在页面加载时仍然被显示。这意味着它既无法通过 required 验证,也无法通过约束验证。我认为这是 Chrome 的一个 bug。


我也阅读了有关有效浮点数的规范。0. 看起来应该解析为 0,因此会导致有效性对象上设置下溢标志。在我看来,这似乎是一个错误。 - CodingIntrigue
实际上,@robertc最后一段是不正确的。在Chrome中,document.querySelector("#one").value返回"0."-请参见http://jsfiddle.net/qa9orh37/。我深入挖掘了Chromium源代码并找到了问题,这是`rangeUnderflow`和`badInput`解析之间的不一致性-请参见我的答案。 - CupawnTae
@CupawnTae 在我工作的Windows PC上,我得到了空字符串,在我家里的Linux笔记本电脑上,我看到像你一样的“0.”。我明天会再次检查工作PC,以确保我没有想象任何东西 :) - robertc
很奇怪 - 在Windows 7上,无论是Chrome 37.x还是38.x-beta,我都得到了“0.”。我的钱投在宇宙射线上;) 无论如何,即使我得到了“0.”(和valueAsNumber的0),它仍然给出了rangeUnderflow === false,这证实了我从Chrome源代码中得出的结论。 - CupawnTae
@CupawnTae 好的,我在Windows 7上也得到了0.。昨天我尝试了几种变化,可能把自己搞混了。 - robertc

0
据我所知,验证的value属性正在使用html5的valueAsNumber功能进行解析。这与JavaScript有不同的规则,因此在FF32中:
var el = document.createElement("input");
el.type = "number";
el.value = "1";
el.valueAsNumber;
/*
1
*/

但是

var el = document.createElement("input");
el.type = "number";
el.value = "0.";
el.valueAsNumber;
/*
NaN
*/

如果“0.”被解析为NaN,那么我认为验证被绕过了。

2
Chrome正确地将“0.”的数字值报告为0。而其他非数字值(例如“aaa”)可能也会产生NaN值,但是它们会正确地失败,而“0.”则错误地通过了。也许valueAsNumber是其中一部分原因,但似乎并不能完全解释这个问题。 - apsillers
1
@apsillers 实际上,如果你在第二个例子中用 "aaa" 替换 "0.",它在 Chrome 中会显示为有效 - 这似乎是在代码中设置值和用户输入到输入框中之间的差异。 - CupawnTae
而且也许有关联的是,如果你在 DOM 中的一个输入框中以编程方式将其设为 "aaa",它将显示为空白,而 "0." 将显示在屏幕上。这可能是因为 "0." 至少正在成为一个有效数字,而 "aaa" 不是。 - CupawnTae

0

在输入类型为数字的情况下,包含是一个浮点数

浮点数由以下部分组成,且顺序如下:

  1. 可选地,第一个字符可以是“-”字符。
  2. 一个或多个范围在“0-9”的字符。
  3. 可选地,以下部分,且顺序如下:
    1. 一个“.”字符
    2. 一个或多个范围在“0-9”的字符
  4. 可选地,以下部分,且顺序如下:
    1. 一个“e”字符或“E”字符
    2. 可选地,一个“-”字符或“+”字符
    3. 一个或多个范围在“0-9”的字符。

你可能知道在浮点数中,0. == 0.0 == 0。像其他的0和0.0一样,验证是正确的,所以0.也是一个正确的验证。


3
这个回答似乎没有涉及到关键问题,即 0.0 被正确地验证为小于 1,但 0. 却没有被验证为小于 1 - apsillers
另外,根据规范,0.不是有效的浮点数。http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#valid-floating-point-number - CupawnTae

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