HTML <input type="number"> 在移动设备上的最佳设置是什么?

15

我已经阅读了许多其他问题,例如这些[1][2][3] ,但问题仍然存在。

我需要找到一种适用于移动设备的HTML input 的“最干净”方法,并符合以下三个规则:

  1. 主要适用于数字,整数或浮点数

  2. 在Chrome for Android和Safari for iOS上,在移动设备上显示数字键盘,没有奇怪的额外键

    输入图像描述

  3. 完全遵守HTML5规则,经过W3C验证器测试


我试过什么?

我尝试了这些解决方案,但没有哪一个同时满足上述三个规则。

解决方案1

<input type="text" pattern="\d*" />

在此输入图像描述

尽管这个解决方案在iOS上工作并符合W3C验证器测试的HTML规则,但在Chrome Android上会显示带有QWERTY键盘的完整键盘。

解决方案2

<input type="number" pattern="\d*" />

这种解决方案适用于iOS和Android Chrome系统,在这两个系统上都会显示数字键盘,但它会在W3C验证器中抛出HTML验证错误:

pattern属性仅允许在输入类型为电子邮件、密码、搜索、电话、文本或网址时使用。

解决方案3

<input type="number" />

这个解决方案通过了W3C HTML测试,在Chrome上显示良好,但在iOS键盘上出现了几个不需要的按键

输入图像描述

解决方案4

我看到很多开发人员使用这种解决方案

<input type="tel" />

然而在Android Chrome中,不允许使用点符号.(因此没有浮点数),并且按键上有字母,这是多余的。

chrome input type="tel"


1
那么明确一下,您有一种适用于iOS的方法和一种适用于Android的方法,但两者都不兼容?如果是这样,您可以检测用户所使用的操作系统(请参见此处),然后根据操作系统使用相应的解决方案。 - Alex Charters
@Alex,解决方案2适用于两个系统,这是我使用的方案,但在W3验证器上会出现HTML错误。 - João Pimentel Ferreira
嗯,如果您坚持要使用W3的验证,我不知道有什么办法使选项2起作用。您不能进行上述系统检查有什么原因吗? - Alex Charters
1
@Alex,根据所有后续的jQuery函数所假设的某种输入模式,相应地更改输入将会使事情变得过于复杂。我想知道是否有可能获得一个“静态”的解决方案。 - João Pimentel Ferreira
是的,听起来应该可以。这可能是一个折中方案,但这是我所拥有的最好的解决方法。祝你好运。 - Alex Charters
显示剩余3条评论
5个回答

7
针对您的具体任务,我有一种非常出色的解决方案:我们可以选择最佳的 type="text" 和 pattern,并添加 JavaScript 来更正 type 属性。这样做可以通过 W3 验证器。 解决方案
// iOS detection from: stackoverflow.com/a/9039885 with explanation about MSStream
if(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
{
    var inputs = document.querySelectorAll('input[type="number"]');
    for(var i = inputs.length; i--;)
        inputs[i].setAttribute('pattern', '\\d*');
}

<input type="number" />

我的解决方案遵守你提出的三条规则(包括W3验证器)。

但我必须提到,在这种情况下(使用模式),在iOS上我们无法使用带有数字键盘的浮点数,因为在iOS上我们没有任何包括点的数字键盘。在Android上我们有这个可能性。如果您想要带有浮点数的数字键盘,则需要为iOS编写额外的解决方案,如下所示:

 <input type="number" />

为什么如果“属性模式仅在输入类型为电子邮件、密码、搜索、电话、文本或网址时才允许”,那么它会通过W3验证器呢?或者为什么不默认使用type="number",然后再添加代码pattern呢? - João Pimentel Ferreira
@JoãoPimentelFerreira,因为W3验证器不会检查JavaScript。 W3验证仅用于检查您的代码。这可以帮助您找到代码中的错误,但这不是规定。至于第二个问题:这是相同的解决方案-您也可以以这种方式完成,这是偏好的问题。 - Bharata
pattern="\d*" 修复似乎在 iPad 上不再起作用(我在 iOS12.2 Beta 中注意到了这一点),因此我们使用 type=tel。 - robocat
有很多资源可以告诉你为什么不应该进行用户代理检测,例如:CSS-TricksWebAIMMezzoblueQuirksModeGitHub等。其中一个主要原因是,当新的浏览器推出并且现有的浏览器变得更好时,您将不得不不断更新代码,而浏览器需要不断寻找绕过未更新的检测代码的技巧。 - Peter

7
还有另一种选择:<input type="text" inputmode="numeric" pattern="[0-9]*">。详见为什么英国GOV.UK设计团队改变了数字输入类型。请注意,如果您仍然想使用<input type="number">,则可以通过关闭数字输入微调器来解决问题4-滚动。每种解决方案似乎都有一些缺点,我认为最适合的取决于您尝试收集的数据类型,如护照号码、年龄或物品数量。我发现这种解决方案的缺点有:1.输入值现在是文本而不是数字,因此您可能需要在JS中进行额外的解析;2.在桌面浏览器上,该输入将接受字母字符,表格将无效,但您需要处理并显示相关的用户反馈(如果使用框架,可能会自动完成);3.它仅由现代移动浏览器支持,例如iOS 12.2上的Safari(约2019)(请参阅规范)。

3
我发现这个问题,以下两种解决方案似乎是回答这个问题的最佳方法。
第一个解决方案非常简单,在Android和IOS上都可用。这个解决方案将在桌面上有一个上下按钮,在Android和IOS上只有一个数字键盘。

<form action="" method="">
<input pattern="[0-9]*"/>
</form>

这个解决方案唯一的问题是用户无法输入逗号或句号,因为它们不会显示在键盘上。如果您更改模式,则上述内容将无法在IOS上运行。
第二种解决方案不被所有浏览器支持,但似乎在所有现代浏览器中都可以使用,包括Safari 15.1。

<input inputmode="numeric" pattern="[0-9]*" type="text"/>

要查看支持inputmode的浏览器,请点击这里

祝好运


这个“pattern”支持正则表达式吗?如果是,为什么不加上点呢?像 [0-9.]* 这样。 - João Pimentel Ferreira
1
嗨,João,由于某种原因,当您向正则表达式添加其他内容时,苹果会显示普通键盘。但需要注意的是,有一个区别,即如果将正则表达式模式设置为[0-9.]*,IOS设备将打开完整键盘的数字和字符部分,这对用户体验仍然很糟糕。获取带有全屏数字键盘的逗号和句号的唯一其他方法是使用type="tel",如上所建议。最好的问候 - Web Dev

1

如评论中所述,由于没有直接的方法来实现这一点,最好的解决方法是始终使用带有if语句的input type="number",如果设备是iOS设备,则代码将添加适当的pattern属性到类型中。


为了全面起见,您能否添加完整的代码? - João Pimentel Ferreira
请注意,在 iPhone 上,即使使用 step=anytype=number 不允许输入小数点。(对于某些版本的 Android 或 Chrome 或 Android 键盘,step=any 可以在手机上显示小数点)。您还可以尝试为 Chrome 设置 inputmode=decimal - https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inputmode - robocat

0

根据 @Alex Charters 的建议,我提出了这个解决方案,使用 jQuery,它似乎更快,更优雅。

将这段代码添加到页面的“onload”中

//shows numeric keypad on iOS mobile devices
if(getMobileOperatingSystem() === "iOS"){
    $('input[type="number"]').attr("pattern", "\\d*");
}

操作系统检测功能是这样的,取自其他SO答案
/**
 * Determine the mobile operating system.
 * This function returns one of 'iOS', 'Android', 'Windows Phone', or 'unknown'.
 *
 * @returns {String}
 */
function getMobileOperatingSystem() {
  var userAgent = navigator.userAgent || navigator.vendor || window.opera;

      // Windows Phone must come first because its UA also contains "Android"
    if (/windows phone/i.test(userAgent)) {
        return "Windows Phone";
    }

    if (/android/i.test(userAgent)) {
        return "Android";
    }

    // iOS detection from: https://dev59.com/EGox5IYBdhLWcg3wr2To#9039885
    if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
        return "iOS";
    }

    return "unknown";
}

我测试过了,它满足了三个规则。当操作系统为iOS时,它会添加pattern属性。我不默认执行它,因为我意识到该代码片段根据输入数量需要一些时间来处理,因此只会在假定为iOS操作系统时运行。


1
jQuery从来没有比原生JS更快。这就像C++和汇编语言一样。而且你还要考虑加载100千字节的jQuery库代码和许多jQuery对象到浏览器内存中的问题。jQuery代码并不优雅。 - Bharata
不要忘记,此悬赏是由您提供的,您不能将赏金授予自己的答案。因为所有这些,我不明白为什么您提供与我的解决方案相同的解决方案,但又不想将赏金授予我的答案?这不是公平竞争! - Bharata
@Bharata 我非常清楚我不能把赏金颁给自己。我对你的方法有问题是因为你总是运行代码,而且这种方法只能在iOS操作系统上运行。 - João Pimentel Ferreira
但是在这背后(始终运行代码)有非常重要的意义:1. 您无法知道客户端使用哪个操作系统 - 可能不是Android或iOS。我们有很多这样的客户端,可能会遇到与iOS相同的问题。2. 这段代码很小,您可以节省服务器和客户端资源以传输额外的代码来检查操作系统。传输它并没有真正的意义。3. 在您的任务中没有提到检查操作系统。但是如果您需要,我可以将操作系统检查添加到我的代码中。我应该这样做吗? - Bharata
为什么需要添加额外的类? - João Pimentel Ferreira
显示剩余8条评论

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