在 Chrome 中不再允许 input type="number" 上的 selectionStart/selectionEnd
Posted
技术标签:
【中文标题】在 Chrome 中不再允许 input type="number" 上的 selectionStart/selectionEnd【英文标题】:selectionStart/selectionEnd on input type="number" no longer allowed in Chrome 【发布时间】:2019-01-09 06:46:32 【问题描述】:我们的应用程序在输入字段上使用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
有什么方法可以确定类型=“数字”的输入字段中插入符号的位置?
【问题讨论】:
嗯,没有更新。很好奇为什么要删除此功能。 另一种利用方式:如果你使用jquery-maskmoney插件输入类型号,也会出现同样的问题 能否将输入类型暂时更改为text
,检查插入符号位置,然后将类型更改回number
?
@Stan 我认为交换类型不是很可行,尽管我还没有尝试过。
@Steven 它不起作用,selectionStart/End 总是返回为零:jsfiddle.net/Mottie/wMYKU
【参考方案1】:
Selection is only permitted with text/search, URL, tel and password。对类型 number 的输入禁用选择的可能原因是,在某些设备上,或在某些情况下(例如,当输入显示为短 list
时),可能没有插入符号。我找到的唯一解决方案是将输入类型更改为文本(使用适当的模式来限制输入)。我仍在寻找一种不改变输入类型的方法,当我找到一些东西时会发布更新。
【讨论】:
我了解某些设备可能不会显示插入符号,但这似乎会使事情复杂化。如果我们最终对所有内容都使用 type="text" ,那么它甚至会破坏拥有类型的目的。它也失去了手机为数字输入等显示不同键盘的能力。我不同意他们从输入中删除选择的选择,但我不确定解决方案是什么...... 这真的很糟糕。我已经就此联系了 WHAT-WG,因为我认为这是一个重大错误。 99.9% 的用户代理将<input type="number"/>
字段呈现为文本字段,该字段将默认屏幕键盘(如果可用)设置为数字键盘,但仍将该字段呈现为“文本输入”字段。任何现有/未来为该字段添加计算器或类似值操作功能的尝试现在都变得无用,除非我们将字段强制恢复为文本并破坏用户体验。
我同意你们两个。正如我在this 帖子中指出的那样,我认为 value IDL 属性应该始终包含输入包含的任何内容的文本呈现。此外,如果用户代理允许选择,则 selectionStart/End 应该可用。
Whaaaaat o_0 Chrome 刚刚破坏了互联网.. 和我的测试。更严重的是,我不明白逻辑。为什么用户不能选择他们的电子邮件地址或号码? ***.com/questions/22171694/…【参考方案2】:
我为setSelectionRange()
找到了一个简单的解决方法(在 Chrome 上测试)。您可以在使用setSelectionRange()
之前将type
更改为text
,然后将其更改回number
。
这是一个使用 jquery 的简单示例,每当您单击输入时,它会将插入符号定位在数字输入中的位置 4(在输入中添加超过 5 个数字以查看行为)
plunker
【讨论】:
这种方法也适用于email
输入(这就是我最终在这个页面上想知道为什么setSelectionRange()
在IE11(!)而不是Chrome 中工作的原因)。
这在没有 jQuery 的情况下工作,作为纯 javascript obj.type = "text";然后返回 obj.type = "number";
但是 plunkr 不再允许用户用鼠标进行选择。
对我来说(在 Chrome 版本 80 中)这不再有效,因为如果我使用 input.type = 'text'
将输入类型设置为“文本”,Chrome 会从输入中移除焦点,并且光标会消失,因此 @ 987654330@等返回null。【参考方案3】:
目前唯一允许安全选择文本的元素是:
<input type="text|search|password|tel|url">
如下所述:whatwg: selectionStart attribute。
您还可以阅读 HTMLInputElement interface 的文档以仔细查看输入元素。
为了安全地克服这个“问题”,目前最好的办法是处理<input type="text">
并应用只接受数字的掩码/约束。周围有一些插件可以满足要求:
您可以在此处查看以前插件之一的现场演示:
http://plnkr.co/edit/VPVokB?p=preview如果你想安全地使用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()
【讨论】:
嗨,谢谢你的帖子。你能解释一下“只接受数字的约束”是什么意思吗? 嗨@PetarMI,通过 constraint 我的意思是 元素只能接受数字字符,它是通过 JavaScript 完成的,这是因为并非所有浏览器都能正常工作使用新的 HTML5 标签。【参考方案4】:您可以通过一种方法在 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
我从这个 SO 答案中得到了这个想法:https://***.com/a/24247942
【讨论】:
这太疯狂了,但它确实有效。感谢这个答案!【参考方案5】:这发生在我们使用 jQuery Numeric Plugin 版本 1.3.x 时,因此用 try...catch
包装 selectionStart
和 selectionEnd
我们能够抑制错误。
来源:https://github.com/joaquingatica/jQuery-Plugins/commit/a53f82044759d29ff30bac698b09e3202b456545
【讨论】:
【参考方案6】:作为一种变通方法,type="tel"
输入类型提供了与 Chrome 中的 type="number"
非常相似的功能,并且没有此限制(正如 Patrice 所指出的那样)。
【讨论】:
fwiw 这在 android 上给出了一个电话特定的小键盘,而 number 给出了一个不同的小键盘【参考方案7】:我们不能只反转元素检查以仅包含受支持的元素,如下所示:
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'
)
【讨论】:
【参考方案8】:虽然此类表单字段的已弃用事件的问题可能仍然存在,但据我所知,这种字段可以像往常一样通过“更改”事件进行侦听。
我在寻找此类字段的事件问题的答案时来到了这篇文章,但在测试它时,我发现我可以简单地依赖所提到的“更改”事件。
【讨论】:
【参考方案9】:我在 angularjs 网站中收到此错误。
我在输入上创建了一个自定义数据属性,并且还在使用 ng-blur(带有 $event)。
当我的回调被调用时,我试图访问“data-id”值,例如:
var id = $event.target.attributes["data-id"]
应该是这样的:
var id = $event.target.attributes["data-id"].value
似乎没有太多关于这个错误的地方,所以我把它留在这里。
【讨论】:
【参考方案10】:我知道这个答案来得太晚了,但这里有一个插件,它为所有类型的元素实现了 selectionStart,适用于大多数浏览器(旧的和新的):
https://github.com/adelriosantiago/caret
我已使用@ncohen 的答案对其进行了更新以处理type="number"
问题。
【讨论】:
【参考方案11】:解决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】:如果使用 Chrome 的设备测试模式,请注意 Angular 中的误报。
所以这显然是 Chrome 而不是真正的 iPhone - 但仍然会引发错误,因为 _platform.IOS
返回 true,然后 setSelectionRange
随后失败。
这是 Angular - 但其他框架/环境中可能存在类似问题。
【讨论】:
【参考方案13】:修改event.target
对象中的type属性可以得到光标位置(selectionStart
,selectionEnd
):
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" />
【讨论】:
以上是关于在 Chrome 中不再允许 input type="number" 上的 selectionStart/selectionEnd的主要内容,如果未能解决你的问题,请参考以下文章
如何在 chrome 中更改 <input type=date> 的外观
解决chrome浏览器的input[type=date]的格式问题