如何使用更严格的限制来自定义`<input>`元素

时间:2019-08-30 05:49:28

标签: javascript html

TLDR; (更新)

  1. 是否有一种方法可以通知<input>是数字类型,而无需使用type=number属性设置。
    1. 即移动设备识别并显示数字键盘等
  2. 对于具有<input>的{​​{1}},有一种方法可以吞并所有不会产生有效数字的键输入
    1. 在通过浏览器将字符添加到输入中之前,type=number上不会出现垃圾删除

请阅读以下原始详细说明

我的问题如下:

我有一个html keyup元素,我只想接受数字并在移动设备上被识别为数字字段。我还希望吞下无效字符,就像标准<input>吞咽不允许的字符一样。

我尝试了明显的type=number,但它有很多缺点。具体来说,它允许使用“ e”,“ +”和“-”(至少在chrome中),但是使用JS可以轻松解决这些问题。真正的问题在于“。”字符,我希望能够输入浮点数,例如'0.10','5.5054',但是不想输入例如'0.10.1'之类的无效字符串。我试图通过仅允许1'来解决此问题。一次,但这失败了,因为type=number被浏览器按摩了,例如'5。变为'5','5 ..'变为null(!),并且似乎无法获得在输入​​中键入的原始字符串值。以上意味着检查现有的“。”并采取行动似乎是死路一条...

核心问题:

  1. 有没有一种方法可以检查和验证输入?
  2. “有没有一种方法可以将输入标记为数字,而不必承担input.value的后勤负担?

注意:
*我意识到您可以粘贴您想要的任何内容,我认为这种行为是病态的,因此不应被输入预防所覆盖。

更新:
为了澄清起见,我已经尝试了type=numberkeypress等事件,它们并不足够,因为我想查看当前输入中存在多少个'。,以选择是否允许另一个。此时,浏览器已对keydown进行了按摩,以删除“。”。我想有条件地允许基于当前输入的'。'字符。

示例:
HTML(为简洁起见,使用角度样式绑定)

input.value

JS

<input type="number" (keydown)="keyDown()">

8 个答案:

答案 0 :(得分:15)

  

是否有一种方法可以指示<input>是数字类型,而无需使用type=number属性设置。   即移动设备识别并显示数字键盘等

使用inputmode="decimal"代替type="number"表示移动设备使用数字键盘输入。这样,您可以继续使用type="text"并根据需要处理输入。

有关更多信息,请参见MDN,并在设备上进行测试。{p3}

答案 1 :(得分:3)

一种略有不同的方法。它允许数字,仅1个句点和退格键。 KeyboardEvent.key的其余所有ctrl + v(包括ctrl + c10)将被忽略。但是,如果愿意,可以这样做。

要检查字符是否为event.key数字之一,我使用Digits[0-9],因为它们可以有两个不同的代码:Numpad[0-9]event.code。但是对于期间和退格,我使用const input = document.querySelector("#number_input"); const App = { isDigit: function(key) { const digits = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ]; return digits.includes(key); }, isPeriod: function(code) { return code === "Period"; }, isBackSpace: function(code) { return code === "Backspace"; }, handleEvent: function(event) { const key = event.key; const code = event.code; const value = input.value; if (App.isDigit(key) || App.isPeriod(code) || App.isBackSpace(code)) { if (App.isPeriod(code) && value.indexOf(key) !== -1) { event.preventDefault(); } } else { event.preventDefault(); } } }; input.onkeydown = App.handleEvent,因为它们只有一个代码。

<input id="number_input" />
const input = document.querySelector("#number_input");
const dummyInput = document.querySelector("#dummy_input")
const App = {
  isDigit: function(key) {
    const digits = [
      "0",
      "1",
      "2",
      "3",
      "4",
      "5",
      "6",
      "7",
      "8",
      "9"
    ];
    return digits.includes(key);
  },
  isPeriod: function(code) {
    return code === "Period";
  },
  isBackSpace: function(code) {
    return code === "Backspace";
  },
  handleEvent: function(event) {
    const key = event.key;
    const code = event.code;
    const dummyValue = dummyInput.value;
    if (App.isBackSpace(code)) {
      dummyInput.value = dummyValue.substring(0, dummyValue.length - 1)
    } else {
      if (App.isDigit(key) || App.isPeriod(code)) {
        if (App.isPeriod(code) && dummyValue.indexOf(key) !== -1) {
          event.preventDefault();
        } else {
          dummyInput.value += event.key
        }
      } else {
        event.preventDefault();
      }
    }
  }
};

input.onkeydown = App.handleEvent

聪明的骇客

由于您坚持使用数字输入。首次使用时,您可以使用CSS或Js隐藏虚拟文本输入,并验证其值而不是数字输入。

<input type="number" id="number_input" />
<input type="text" id="dummy_input" />
<input type="number" min="1" id="number_input" />

更新

所有使用input [type =“ number”]的答案都有问题。您可以通过鼠标滚轮/微调器将输入的值更改为负数。要解决此问题,请为输入设置最小值。

onchange

您需要监听const input = document.querySelector("#number_input"); const dummyInput = document.querySelector("#dummy_input") const App = { isDigit: function(key) { const digits = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ]; return digits.includes(key); }, isPeriod: function(code) { return code === "Period"; }, isBackSpace: function(code) { return code === "Backspace"; }, handleEvent: function(event) { const key = event.key; const code = event.code; const dummyValue = dummyInput.value; if (App.isBackSpace(code)) { dummyInput.value = dummyValue.substring(0, dummyValue.length - 1) } else { if (App.isDigit(key) || App.isPeriod(code)) { if (App.isPeriod(code) && dummyValue.indexOf(key) !== -1) { event.preventDefault(); } else { dummyInput.value += event.key } } else { event.preventDefault(); } } }, handleChange: function(event) { dummyInput.value = event.target.value } }; input.onkeydown = App.handleEvent; input.onchange = App.handleChange;事件,然后更改虚拟输入的值。

<input type="number" min="1" id="number_input" />
<input type="text" id="dummy_input" />
paginator

答案 2 :(得分:0)

触发onkeypress

特殊功能,并检查是否键入了允许的字符。如果不是,请阻止默认行为。

let special = document.getElementById('special_input');
special.addEventListener("keypress", function(e) {
  let dot = 46;
  // allowed char: 0-9, .
  let allow_char = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, dot];
  if (allow_char.indexOf(e.which) !== -1) {
    // only 1 dot
    if (e.which == 46 && special.value.indexOf('.') !== -1)
      e.preventDefault();
  } else {
    e.preventDefault();
  }
});
<input id='special_input'>

答案 3 :(得分:0)

已更新

答案随需求变化而更新。

好吧,我尝试解决另一个问题,那就是粘贴

根据以下代码,您不能粘贴任何内容,只能粘贴数字,如果您尝试粘贴字符串,则输入框将自动变为空:)

  let special = document.getElementById('inputField');
  special.addEventListener("keypress", function(e) {
  let dot = 46;
  // allowed char: 0-9, .
  let allow_char = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, dot];
  if (allow_char.indexOf(e.which) !== -1) {
    // only 1 dot
    if (e.which == 46 && special.value.indexOf('.') !== -1)
      e.preventDefault();
  } else {
    e.preventDefault();
  }
});

function checkString()
{
  setTimeout(() => {
  var value = document.getElementById("inputField").value;
  value = parseInt(value);
    if(isNaN(value))
      document.getElementById("inputField").value = "";
    }, 100);

}
  <input type="number" id="inputField" onpaste="checkString()"/>

答案 4 :(得分:0)

通过以下方式检查真实性

value == parseFloat(value)

parseFloat()将捕获第一个小数点并删除所有其他小数点。

使用'=='代替'==='将确保参考值不变。

function keyDown($event: KeyboardEvent) {
    const inputField = // obtain reference to input element
    const value = inputField.value;
    if ( value == parseFloat(value)) { // disallow another . if one is present
      // ! input field prunes . so this check isn't sufficient
      $event.preventDefault();
      return;
    }

    // This is the crux of the problem e.g.
    // type 5. into input field, value === 5
    // type 5.. into the input field, value === null
    // Since the . char is removed by the input element there's no way to know how many are present!
    console.log(value);
  }

这是一个类似的测试,您可以在node.js中运行以验证它是否完成了您想要的工作。

function numCheck (value) {
    if (value == parseFloat(value)) { 
        console.log(value)
    } else {
        console.log('not a number')
    }
}

numCheck("5");
numCheck("5.5");
numCheck("5.5.5");
numCheck("A");

答案 5 :(得分:-1)

对于限制,正则表达式是最好的选择。在按键上注册事件监听器

numbersOnly(event) {
    const numbers = /^([0-9])$/;
    const result = numbers.test(event.key);
    return result;
}

如果函数与正则表达式不匹配,则上述函数将吞下字符集

Javascript Regex: validating a double/float

以上链接具有正则表达式,该正则表达式允许使用double / float。希望对您有所帮助:)

答案 6 :(得分:-1)

也许是您问题的间接解决方案。您可以查看validity属性,以确定输入是否有效。 您可以检查有效性而无需访问该值,如果输入无效,则可能不会返回该值。

HTML:

<input type="number" id="num" step="0.1"/>

JS:

var numField = document.getElementById('num');
numField.addEventListener("keyup", event => {
   if(!numField.validity.valid)
   {
      alert('invalid input');
   }
});

一些测试:

34    -> valid
3.4   -> valid
e     -> invalid
+4    -> valid    
3.4.  -> invalid
3.4.. -> invalid
.4    -> valid (evaluates to 0.4)
3e+2  -> valid
1e    -> invalid
eee   -> invalid
-0.3e+1 -> valid
..32e.. -> invalid

这适用于粘贴和输入值。

更新:

原始问题有点冗长。我正在尝试将其分解并分部分回答。

Input [type =“ number”]仅在有效时允许访问该值,否则返回空。因此,您可以知道值是否正确,但是您不能获得无效的值。

您可以通过将各个按键推入缓冲区来解决此问题。但是,由于复制/粘贴,输入字段吞没某些键,在光标周围移动和插入键等,保持缓冲区与实际值之间的同步具有挑战性。为所有这些实现可靠的跨平台支持似乎是过分的。更好的方法是采用其他方式输入数字,例如滑块。 This resource covers the basics of designing number inputs

因此,您只需要知道当前输入是否有效以及是否按下了最后一个键即可。问题是某些无效输入,例如“4。”可能导致有效的输入“ 4.1”。因此,在输入变为无效的情况下仅吞下最后一个键是不可能的。

您可以实施以下规则:如果在2次击键(或1秒)内未将无效输入转换为有效输入,则输入将返回吞噬无效输入的最后一个有效状态。但是,我认为这会造成UX问题,因为用户可能不习惯这种行为,并且为用户提交技术上有效但不需要的值打开了大门。

  

核心问题:

     
      
  1. 有没有一种方法可以检查和验证输入?

  2.   
  3. 是否有一种方法可以将输入标记为数字,而不必使用类型= number的后勤包?

  4.   
  1. 显然不是。

  2. 是的,这是通过重新考虑如何输入数字值的方式。

答案 7 :(得分:-1)

这可能是您要寻找的:
此输入会吃掉所有数字和“。”以外的角色。

let prev = "";
function keyUp(event) {
    if ((!event.target.value && event.keyCode !== 8) || event.target.value.indexOf('e') !== -1 || parseFloat(event.target.value) == NaN) {
        event.target.value = prev;
    } else {
        prev = event.target.value;
    }
}
<input type="number" onkeyup="keyUp(event)">