selectionStart / selectionEnd输入类型=“数字”不再允许在Chrome中使用

时间:2014-01-17 03:49:25

标签: javascript google-chrome

我们的应用程序在输入字段上使用selectionStart来确定当用户按下箭头键时是否自动将用户移动到下一个/上一个字段(即,当选择位于文本末尾并且用户按下右箭头时我们移动到下一个字段,否则)

Chrome现在阻止在type =“number”的地方使用selectionStart。 它现在抛出异常:

Failed to read the 'selectionStart' property from 'HTMLInputElement': The input element's type ('number') does not support selection.

见以下内容:

https://codereview.chromium.org/100433008/#ps60001

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#do-not-apply

有没有办法在type =“number”的输入字段中确定插入符的位置?

13 个答案:

答案 0 :(得分:37)

Selection is only permitted with text/search, URL, tel and password。对于类型编号的输入禁用选择的可能原因是在某些设备上,或在某些情况下(例如,当输入已经显示为短list)时,可能没有插入符号。我发现的唯一解决方案是将输入类型更改为文本(使用适当的模式来限制输入)。我仍在寻找一种不改变输入类型的方法,并在发现内容时发布更新。

答案 1 :(得分:14)

目前唯一允许安全选择文本的元素是:

<input type="text|search|password|tel|url">如下所述: whatwg: selectionStart attribute

您还可以阅读 HTMLInputElement interface 的文档,详细了解输入元素。

要克服这个问题&#34;问题&#34;安全地,现在最好的是处理<input type="text">并应用仅接受数字的掩码/约束。有一些插件满足要求:

您可以在此处看到之前插件之一的现场演示:

如果您想安全使用selectionStart,那么您可以检查支持它的元素(请参阅input type attributes

实施

// Fix: failed to read the 'selectionStart' property from 'HTMLInputElement'
// The @fn parameter provides a callback to execute additional code
var _fixSelection = (function() {
    var _SELECTABLE_TYPES = /text|password|search|tel|url/;
    return function fixSelection (dom, fn) {
        var validType = _SELECTABLE_TYPES.test(dom.type),
            selection = {
                start: validType ? dom.selectionStart : 0,
                end: validType ? dom.selectionEnd : 0
            };
        if (validType && fn instanceof Function) fn(dom);
        return selection;
    };
}());

// Gets the current position of the cursor in the @dom element
function getCaretPosition (dom) {
    var selection, sel;
    if ('selectionStart' in dom) {
        return _fixSelection(dom).start;
    } else { // IE below version 9
        selection = document.selection;
        if (selection) {
            sel = selection.createRange();
            sel.moveStart('character', -dom.value.length);
            return sel.text.length;
        }
    }
    return -1;
}

用法

// If the DOM element does not support `selectionStart`,
// the returned object sets its properties to -1.
var box = document.getElementById("price"),
    pos = getCaretPosition(box);
console.log("position: ", pos);

上面的例子可以在这里找到:jsu.fnGetCaretPosition()

答案 2 :(得分:14)

我在setSelectionRange()找到了一个简单的解决方法(在Chrome上测试过)。您可以在使用type之前将text更改为setSelectionRange(),然后将其更改回number

这是一个简单的jquery示例,只要您单击输入(在输入中添加超过5个数字以查看行为),就会在数字输入中将插入符号定位在第4位

plunker

答案 3 :(得分:5)

在使用jQuery Numeric Plugin版本1.3.x时,我们发生了这种情况,因此将selectionStartselectionEndtry...catch{}包裹起来,我们就能够抑制错误。

来源:https://github.com/joaquingatica/jQuery-Plugins/commit/a53f82044759d29ff30bac698b09e3202b456545

答案 4 :(得分:5)

作为解决方法,type="tel"输入类型提供与Chrome中type="number"非常相似的功能,并且没有此限制(正如Patrice所指出的那样)。

答案 5 :(得分:5)

有一种方法可以在Chrome上完成此操作(可能还有其他一些浏览器,但Chrome是这里的大罪犯)。使用window.getSelection()从当前输入中检索选择对象,然后测试向后(或向前)扩展选择,并查看选择的toString()值是否更改。如果它没有,则光标位于输入的末尾,您可以移动到下一个输入。如果是,则必须反转操作以撤消选择。

s = window.getSelection();
len = s.toString().length;
s.modify('extend', 'backward', 'character');
if (len < s.toString().length) {
    // It's not at the beginning of the input, restore previous selection
    s.modify('extend', 'forward', 'character');
} else {
    // It's at the end, you can move to the previous input
}

我从这个答案得到了这个想法:https://stackoverflow.com/a/24247942

答案 6 :(得分:3)

我们不能反转元素检查以包含支持的元素,如下所示:

if (deviceIsIOS &&
    targetElement.setSelectionRange &&
    (
        targetElement.type === 'text' ||
        targetElement.type === 'search' ||
        targetElement.type === 'password' ||
        targetElement.type === 'url' ||
        targetElement.type === 'tel'
    )
) {

而不是:

if (deviceIsIOS && 
    targetElement.setSelectionRange && 
    targetElement.type.indexOf('date') !== 0 && 
    targetElement.type !== 'time' && 
    targetElement.type !== 'month'
) {

答案 7 :(得分:1)

虽然这种类型的表单字段的已弃用事件的问题可能仍然相关,但据我所知,可以通过&#34;更改&#34;来收听此类字段。事件,像往常一样。

我在这里找到这篇文章的事件问题的答案,但在测试时,我发现我可以简单地依靠&#34;改变&#34;如上所述。

答案 8 :(得分:1)

我在angularjs网站上收到此错误。

我在输入上创建了自定义数据属性,并且还使用了ng-blur(使用$ event)。

当我的回调被调用时,我试图访问'data-id'值,如:

var id = $event.target.attributes["data-id"]

应该是这样的:

var id = $event.target.attributes["data-id"].value

这个错误在任何地方似乎都没有太多,所以我要离开这里。

答案 9 :(得分:1)

修改selectionStart对象中的type属性可以获得光标位置(selectionEndevent.target):

const input = document.querySelector("input");
input.addEventListener("keyup", (e) => {
  const {target} = e;
  target.setAttribute("type", "text")
  console.log(target.selectionStart, target.selectionEnd)
});
<input type="number" />

答案 10 :(得分:0)

我知道这个答案来得太晚了,但是对于大多数浏览器(旧的和新的)来说,这是一个为所有类型的元素实现selectionStart的插件:

https://github.com/adelriosantiago/caret

我已使用@ncohen的回答更新了它以处理type="number"问题。

答案 11 :(得分:0)

按以下方式解决Failed to read the 'selectionStart' property from 'HTMLInputElement': The input element's type ('number') does not support selection.

var checkFocus = false;
var originalValue = "";
$(document).ready(function() {
  $("input").focus(function() {
    var that = this;
    if ($('#' + $(this).context.id).attr("type") == "text") {
      setTimeout(function() {
        if (that.selectionStart != null || that.selectionEnd != null) {
          that.selectionStart = that.selectionEnd = 10000;
        }
      }, 0);
    } else if ($('#' + $(this).context.id).attr("type") == "number") {
      if (checkFocus) {
        moveCursorToEnd($('#' + $(this).context.id), $(this).context.id);
        checkValue($('#' + $(this).context.id))
        checkFocus = false;
      } else {
        $('#' + $(this).context.id).blur();
      }
    }
  });
});

function FocusTextBox(id) {
  checkFocus = true;
  document.getElementById(id).focus();
}

function checkValue(input) {
  if ($(input).val() == originalValue || $(input).val() == "") {
    $(input).val(originalValue)
  }
}

function moveCursorToEnd(input, id) {
  originalValue = input.val();
  input.val('');
  document.getElementById(id).focus();
  return originalValue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<button onclick="FocusTextBox('textid')">
   <input id="textid" type="number" value="1234" > 
</button>

答案 12 :(得分:0)

如果使用Chrome的设备测试模式,请在Angular中提防误报。

这显然是Chrome,而不是实际的iPhone-但仍然会引发错误,因为_platform.IOS返回true,然后setSelectionRange随后失败。

这是Angular-但其他框架/环境中也可能存在类似的问题。

enter image description here