La entrada de texto HTML solo permite la entrada numérica

Resuelto Julius A asked hace 15 años • 79 respuestas

¿Existe una manera rápida de configurar una entrada de texto HTML ( <input type=text />) para permitir solo pulsaciones de teclas numéricas (más '.')?

Julius A avatar Jan 22 '09 21:01 Julius A
Aceptado

javascript

Puede filtrar los valores de entrada de un texto <input>con la siguiente setInputFilterfunción (admite Copiar+Pegar, Arrastrar+Soltar, atajos de teclado, operaciones del menú contextual, teclas que no se pueden escribir, la posición del cursor, diferentes diseños de teclado, mensajes de error de validez y todos los navegadores) . desde IE 9 ):

// Restricts input for the given textbox to the given inputFilter function.
function setInputFilter(textbox, inputFilter, errMsg) {
  [ "input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
    textbox.addEventListener(event, function(e) {
      if (inputFilter(this.value)) {
        // Accepted value.
        if ([ "keydown", "mousedown", "focusout" ].indexOf(e.type) >= 0){
          this.classList.remove("input-error");
          this.setCustomValidity("");
        }

        this.oldValue = this.value;
        this.oldSelectionStart = this.selectionStart;
        this.oldSelectionEnd = this.selectionEnd;
      }
      else if (this.hasOwnProperty("oldValue")) {
        // Rejected value: restore the previous one.
        this.classList.add("input-error");
        this.setCustomValidity(errMsg);
        this.reportValidity();
        this.value = this.oldValue;
        this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
      }
      else {
        // Rejected value: nothing to restore.
        this.value = "";
      }
    });
  });
}

Ahora puede utilizar la setInputFilterfunción para instalar un filtro de entrada:

setInputFilter(document.getElementById("myTextBox"), function(value) {
  return /^\d*\.?\d*$/.test(value); // Allow digits and '.' only, using a RegExp.
}, "Only digits and '.' are allowed");

Aplica tu estilo preferido a la input-errorclase. He aquí una sugerencia:

.input-error{
  outline: 1px solid red;
}

Tenga en cuenta que aún debe realizar la validación del lado del servidor .

Otra advertencia es que esto romperá la pila de deshacer ya que se establece this.valuedirectamente. Esto significa que CtrlZno funcionará para deshacer las entradas después de escribir un carácter no válido.

Manifestación

Consulte la demostración de JSFiddle para obtener más ejemplos de filtros de entrada o ejecute el fragmento de pila a continuación:

Mostrar fragmento de código

Mecanografiado

Aquí hay una versión TypeScript de esto.

function setInputFilter(textbox: Element, inputFilter: (value: string) => boolean, errMsg: string): void {
  ["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout" ].forEach(function(event) {
    textbox.addEventListener(event, function(this: (HTMLInputElement | HTMLTextAreaElement) & { oldValue: string; oldSelectionStart: number | null, oldSelectionEnd: number | null }) {
      if (inputFilter(this.value)) {
        this.oldValue = this.value;
        this.oldSelectionStart = this.selectionStart;
        this.oldSelectionEnd = this.selectionEnd;
      }
      else if (Object.prototype.hasOwnProperty.call(this, "oldValue")) {
        this.value = this.oldValue;
        
        if (this.oldSelectionStart !== null &&
          this.oldSelectionEnd !== null) {
          this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
        }
      }
      else {
        this.value = "";
      }
    });
  });
}

jQuery

También hay una versión jQuery de esto. Vea esta respuesta .

HTML5

HTML5 tiene una solución nativa <input type="number">(consulte la especificación y la documentación ). La documentación tiene una demostración funcional de este tipo de entrada.

  • En lugar de leer la valuepropiedad, lea la valueAsNumberpropiedad de la entrada para obtener el valor escrito como un número en lugar de una cadena.
  • Se recomienda el uso dentro de a <form>porque de esta manera se facilita la validación; por ejemplo, al presionar Enterse mostrará automáticamente un mensaje de error si el valor no es válido.
    • Puede utilizar el checkValiditymétodo o el requestSubmitmétodo en todo el formulario para comprobar explícitamente la validez.
    • Tenga en cuenta que es posible que necesite utilizar el requiredatributo para no permitir una entrada vacía.
  • Puede utilizar el checkValiditymétodo o la validitypropiedad en el propio elemento de entrada para comprobar explícitamente la validez.
  • Puede utilizar reportValiditypara mostrar un mensaje de error y utilizar setCustomValiditypara configurar su propio mensaje.

Este enfoque tiene fundamentalmente una experiencia de usuario diferente: se le permite ingresar caracteres no válidos y la validación se realiza por separado . Esto tiene la ventaja de que la pila de deshacer ( CtrlZ) no se romperá. Tenga en cuenta que se debe realizar la validación del lado del servidor, independientemente del enfoque que elija.

Pero tenga en cuenta que la compatibilidad con el navegador varía:

  • La mayoría de los navegadores solo validarán la entrada al enviar el formulario y no al escribir.
  • La mayoría de los navegadores móviles no admiten los stepatributos miny max.
  • Chrome (versión 71.0.3578.98) todavía permite al usuario ingresar los caracteres een Eel campo. Consulte también las Preguntas y respuestas ¿ Por qué la entrada HTML permite ingresar type="number"la letra en el campo? e.
  • Firefox (versión 64.0) y Edge (EdgeHTML versión 17.17134) aún permiten al usuario ingresar cualquier texto en el campo.

Manifestación

document.querySelector("form").addEventListener("submit", (event) => {
  event.preventDefault();
  console.log(`Submit!
  Number is ${event.target.elements.number.valueAsNumber},
  integer is ${event.target.elements.integer.valueAsNumber},
  form data is ${JSON.stringify(Object.fromEntries(new FormData(event.target).entries()))}.`);
})
label {
  display: block;
}
<form>
  <fieldset>
    <legend>Get a feel for the UX here:</legend>
    <label>Enter any number: <input name="number" type="number" step="any" required></label>
    <label>Enter any integer: <input name="integer" type="number" step="1" required></label>
    <label>Submit: <input name="submitter" type="submit"></label>
  </fieldset>
</form>
Expandir fragmento

emkey08 avatar Jan 22 '2009 14:01 emkey08

Utilice este DOM

<input type='text' onkeypress='validate(event)' />

Y este guión

function validate(evt) {
  var theEvent = evt || window.event;

  // Handle paste
  if (theEvent.type === 'paste') {
      key = event.clipboardData.getData('text/plain');
  } else {
  // Handle key press
      var key = theEvent.keyCode || theEvent.which;
      key = String.fromCharCode(key);
  }
  var regex = /[0-9]|\./;
  if( !regex.test(key) ) {
    theEvent.returnValue = false;
    if(theEvent.preventDefault) theEvent.preventDefault();
  }
}
geowa4 avatar Jan 22 '2009 14:01 geowa4

Aquí hay uno simple que permite exactamente un decimal, pero no más. El evento de entrada utiliza expresiones regulares para reemplazar texto sobre la marcha según los dos patrones:

  1. Elimina todo lo que no sea un dígito o un punto.
  2. Eliminar cualquier segunda instancia de un punto

<input type="text" oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1');" />
Expandir fragmento

Como alguien comentó a continuación, la solución anterior no maneja ceros a la izquierda. Si su caso de uso particular requiere que estos no estén permitidos, puede agregarlos al patrón anterior de esta manera:

<input type="text" oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1').replace(/^0[^.]/, '0');" />
Expandir fragmento

Eso permitirá 0.123o .123pero no 0123o 00.123.

He buscado durante mucho tiempo una buena respuesta a esto, y la necesitamos desesperadamente <input type="number", pero aparte de eso, estas 2 son las formas más concisas que se me ocurren:

<input type="text" 
           onkeyup="this.value=this.value.replace(/[^\d]/,'')">

Si no le gusta el carácter no aceptado que se muestra durante una fracción de segundo antes de borrarlo, el siguiente método es mi solución. Tenga en cuenta las numerosas condiciones adicionales, esto es para evitar deshabilitar todo tipo de navegación y teclas de acceso rápido. Si alguien sabe cómo compactar esto, ¡háganoslo saber!

<input type="text" 
onkeydown="return ( event.ctrlKey || event.altKey 
                    || (47<event.keyCode && event.keyCode<58 && event.shiftKey==false) 
                    || (95<event.keyCode && event.keyCode<106)
                    || (event.keyCode==8) || (event.keyCode==9) 
                    || (event.keyCode>34 && event.keyCode<40) 
                    || (event.keyCode==46) )">
user235859 avatar Aug 04 '2010 09:08 user235859

La mayoría de las respuestas aquí tienen la debilidad de utilizar eventos clave .

Muchas de las respuestas limitarían su capacidad para seleccionar texto con macros de teclado, copiar y pegar y más comportamientos no deseados, otras parecen depender de complementos jQuery específicos, que matan moscas con ametralladoras.

Esta solución simple parece funcionar mejor para mí en varias plataformas, independientemente del mecanismo de entrada (pulsación de tecla, copiar y pegar, hacer clic derecho en copiar y pegar, voz a texto, etc.). Todas las macros del teclado de selección de texto seguirían funcionando e incluso limitarían la capacidad de establecer un valor no numérico mediante un script.

function forceNumeric(){
    var $input = $(this);
    $input.val($input.val().replace(/[^\d]+/g,''));
}
$('body').on('propertychange input', 'input[type="number"]', forceNumeric);
EJTH avatar Apr 27 '2015 17:04 EJTH