如何克服WhatWG/W3C/Chrome版本33.0.1750.146中<input type="number"/>字段的“回归错误”

13

我在引号中使用了“回归错误”这个词,因为显然对此存在一些不同的意见。要获取完整的详细信息,请跟踪Bug 24796在Bugzilla中。

简而言之,Google Chrome根据最新版本的WhatWG规范实施了更改:http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary<input type="number"/>字段中删除了以下属性和方法。

属性:

  • selectionStart
  • selectionEnd

方法:

  • select()
  • setSelectionRange(start, end)

(还有其他的,但这些是常用的关键部分)

如果您检查一个“数字”HTMLInputElement实例,那么这些方法将被定义,但是尝试调用这些方法或请求属性将会抛出异常。:-(
在我看来,这是一个错误(因为功能已被删除而没有得到任何收益...并且有成千上万的网站/应用程序通过JavaScript为这些数字输入字段提供了扩展行为...但我偏离了主题(对于那些希望争论的人,请使用上面列出的错误帖子))
为了可用性目的,我肯定希望并计划继续使用<input type="number"/>字段,因为它们向用户代理提供了一个“提示”,如果在移动设备(智能手机/平板电脑/?)上,当该字段聚焦时,我想呈现数字键盘而不是默认的字母键盘。
然而,对于当前版本的Chrome(ver 33.0.1750.146)和任何其他盲目实现此规范更改的浏览器,我希望安全地将呈现的字段转换回<input type="text"/> 注:
尝试在修改内容时动态更改这些字段已被证明是不成功的,因为当类型属性更改时,该字段会失去其选择范围。我有一个解决方法,不久将发布,但我想确保这个问题/答案对于遇到此问题的所有开发人员都在这里。

1
听起来非常令人沮丧。然而,目前它更像是对决定的抱怨,而不是寻求建议的帖子。此外,这是一个重复的问题https://dev59.com/mGEi5IYBdhLWcg3wjczE。 - Benjamin Gruenbaum
另一个问题类似但不完全相同(更重要的是没有解决方案)...我只是在等待定时锁定过期后才能发布我的答案。 - scunliffe
1
你应该考虑在那个问题上发布你的解决方案。 - Benjamin Gruenbaum
此外,如果您打算自己回答问题,请在提问时勾选相应的复选框,这样可以避免被时间锁定。 - Kevin B
@KevinB 谢谢,我不知道这个 - 如果我将来需要再做一次,我会记住的。 - scunliffe
1
感谢您在W3上报告此问题。我已删除我的问题,因为有更好的问题(这个和关于selectionStart的问题),它们已经存在(当我搜索该问题时没有找到)。 - Eric L.
2个回答

4
我用以下代码解决了这个问题:
function checkForInputTypeNumberBug(){
  var dummy = document.createElement('input');
  try {
    dummy.type = 'number';
  } catch(ex){
    //Older IE versions will fail to set the type
  }
  if(typeof(dummy.setSelectionRange) != 'undefined' && typeof(dummy.createTextRange) == 'undefined'){
    //Chrome, Firefox, Safari, Opera only!
    try {
      var sel = dummy.setSelectionRange(0,0);
    } catch(ex){
      //This exception is currently thrown in Chrome v33.0.1750.146 as they have removed support
      //for this method on number fields. Thus we need to revert all number fields to text fields.
      $('input[type=number]').each(function(){
        this.type = 'text';
      });
    }
  }
}
$(document).ready(function(){
  checkForInputTypeNumberBug();
});

我已经将它制作成了一个独立的函数,因为我的一些情况需要通过AJAX加载字段,并且需要能够随时调用该函数。

这段代码处理了旧版IE,在尝试设置类型时会失败的情况,同时还在Chrome(在虚拟元素上)中处理了异常,使页面可以克服这种行为变化。

更新:根据@Andy E关于使用inputmode属性(目前不支持)的建议,我创建了一个错误来尝试优先实现inputmode,以免用户代理删除选择APIs:https://www.w3.org/Bugs/Public/show_bug.cgi?id=26695


1
+1 - 对于支持调整IME的移动浏览器,也许值得添加this.inputMode = 'number'|'email'以支持这些输入类型。 - Andy E
是的,我现在也在做这个 - 但目前支持非常有限。 - scunliffe

0
根据使用情况,可能有更合适(尽管是复杂的)的解决方法。例如,在当前光标位置添加文本,您可以执行以下操作(已在Chrome中进行测试):
var len, pre, post,

    // Currently focused element
    a = document.activeElement,

    // Get current selection
    s = window.getSelection();

// Delete any existing contents
s.deleteFromDocument();

// Keep moving selection backward until the length stops increasing
do {
    len = String(s).length;
    s.modify('extend', 'backward', 'line');
}
while (String(s).length !== len);

// Store the selection, then delete it
pre = String(s);
s.deleteFromDocument();

// Keep moving selection forward until the length stops increasing
do {
    len = String(s).length;
    s.modify('extend', 'forward', 'line');
}
while (String(s).length !== len);

// Store the selection, then delete it
post = String(s);
s.deleteFromDocument();

// Recreate the contents with the new text added
a.setAttribute('value', a.defaultValue);
a.value = pre + txt + post;

// Move the selection to after the new text
a.select();
s = window.getSelection();
s.collapseToEnd();

while (len-- > 0)
    s.modify('move', 'backward', 'character');

这种方法存在局限性,可能需要更加复杂的解决方案,例如当返回的值与所选文本不同(例如在type="email"输入中的阿拉伯域名),就需要采取其他措施。

可悲的是,在Firefox / Gecko中有一个错误,导致此解决方法无法正常工作,但至少Firefox仍允许在<input type="email">上使用Selection API。


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