Desactivar el desplazamiento en `<tipo de entrada = número>`

121

¿Es posible desactivar la rueda de desplazamiento cambiando el número en un campo de número de entrada? Me he metido con CSS específico de webkit para eliminar la ruleta, pero me gustaría deshacerme de este comportamiento por completo. Me gusta usarlo type=numberya que muestra un buen teclado en iOS.

kjs3
fuente
7
utilice el tipo de entrada tel (tipo = "tel") en lugar de utilizar el tipo = número. Aparecerá un teclado numérico de iOS.
Praveen Vijayan
¿Qué sucede cuando agrega un onscrollcontrolador solo event.preventDefault()en él?
robertc
14
En mi humilde opinión, ni siquiera creo que esto deba ser una característica. Si tuviera algo que decir en el desarrollo del navegador, probablemente presionaría para eliminar esta función. No es más que molesto, y no conozco a nadie que realmente lo use.
Kirkland
3
Estoy totalmente de acuerdo contigo Kirkland. Es simplemente una mala experiencia de usuario desplazarse por una página con un formulario y, cuando un elemento de entrada numérico pasa por debajo del mouse, comienza a incrementarse y la página deja de desplazarse. Totalmente desorientador.
kjs3
3
@PraveenVijayan: Aunque esta es una solución alternativa, va en contra de cualquier razón para usar los nuevos tipos de entrada html5. En el futuro, es posible que los teléfonos le brinden la posibilidad de elegir un número de contactos o cualquier cosa, lo que se verá muy extraño si quisiera que este sea un tipo diferente de número.
asombro

Respuestas:

92

Evite el comportamiento predeterminado del evento de rueda del mouse en elementos de número de entrada como lo sugirieron otros (llamar a "blur ()" normalmente no sería la forma preferida de hacerlo, porque eso no sería lo que el usuario desea).

PERO. Evitaría escuchar el evento de la rueda del mouse en todos los elementos de número de entrada todo el tiempo y solo lo haría cuando el elemento está enfocado (ahí es cuando existe el problema). De lo contrario, el usuario no puede desplazarse por la página. cuando el puntero del mouse está en cualquier lugar sobre un elemento de número de entrada.

Solución para jQuery:

// disable mousewheel on a input number field when in focus
// (to prevent Cromium browsers change the value when scrolling)
$('form').on('focus', 'input[type=number]', function (e) {
  $(this).on('wheel.disableScroll', function (e) {
    e.preventDefault()
  })
})
$('form').on('blur', 'input[type=number]', function (e) {
  $(this).off('wheel.disableScroll')
})

(Delegue los eventos de enfoque al elemento de formulario circundante, para evitar a muchos oyentes de eventos, que son perjudiciales para el rendimiento).

Grantzau
fuente
2
Gran respuesta. Creo que si estuviera haciendo esto hoy, usaría Modernizr.touch para aplicar condicionalmente el detector de eventos en dispositivos no táctiles. Básicamente lo que dijo user2863715 a continuación.
kjs3
Excelente respuesta, pero al menos en webkit, esto también evita que la ventana se desplace mientras el cursor está sobre el elemento de entrada. Pensé que los eventos de la rueda del ratón también debían burbujear.
Ryan McGeary
Cuando solo se aplica la función de desactivación de desplazamiento a un elemento cuando está enfocado, esto no debería evitar el desplazamiento, cuando el mouse está sobre el elemento de entrada. Pero evita que se desplace la ventana cuando el elemento está enfocado. Y sí, ¿por qué el evento de la rueda del ratón no burbujea ...?: /
Grantzau
6
Esta es una buena solución para un comportamiento que no debería existir en primer lugar.
Jonny
Esto no funciona en la mayoría de plataformas de tipo Unix gnome, osx, android (con mouse) ya que el comportamiento de desplazamiento no requiere que la entrada esté enfocada. Alternativamente, solo usé el tipo de texto de entradas y le puse mi restricción de número (perdiendo el atajo de teclas arriba / abajo, pero también se puede agregar con js)
zeachco
40
$(document).on("wheel", "input[type=number]", function (e) {
    $(this).blur();
});
Stovroz
fuente
2
este es el que es perfecto.
Patrik Laszlo
Funciona bien. Gracias.
Vijay S
20

Un oyente de eventos para gobernarlos a todos

Esto es similar a @Simon Perepelitsa 's respuesta en js puros, pero un poco más simple, ya que pone un detector de eventos en el elemento documento y comprueba si el elemento enfocado es la inserción de números:

document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number"){
        document.activeElement.blur();
    }
});

Si desea desactivar el comportamiento de desplazamiento de valores en algunos campos, pero no en otros, haga lo siguiente:

document.addEventListener("wheel", function(event){
    if(document.activeElement.type === "number" &&
       document.activeElement.classList.contains("noscroll"))
    {
        document.activeElement.blur();
    }
});

con este:

<input type="number" class="noscroll"/>

Si una entrada tiene la clase noscroll, no cambiará en el desplazamiento; de lo contrario, todo permanece igual.

Prueba aquí con JSFiddle

Peter Rakmanyi
fuente
Veo que esto ha sido rechazado. Si ve un problema, deje un comentario también con el voto negativo. Si me perdí algo, me gustaría saber qué es. Gracias.
Peter Rakmanyi
1
Para el navegador moderno, use evento en wheellugar de mousewheel. Referencia: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event PS. No soy yo quien vota en contra.
vee
19
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

http://jsfiddle.net/bQbDm/2/

Para obtener un ejemplo de jQuery y una solución entre navegadores, consulte la pregunta relacionada:

Detector de eventos HTML5 para desplazamiento de entrada de números: solo Chrome

Simón Perepelitsa
fuente
2
Gracias Seymon, me las arreglé para hacerlo para todas las entradas de números con jQuery de esta manera: $(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });utilicé el desenfoque en lugar de evitar el valor predeterminado para que no bloquee el desplazamiento de la página.
Thibaut Colson
Buena adición sobre el desenfoque, no sabía que aún se puede permitir el desplazamiento de página. Actualicé mi respuesta.
Simon Perepelitsa
13
FYI, live()está en desuso. Ahora, debe usar on(): $(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
Saeid Zebardast
3
@SaeidZebardast Su comentario merece ser una respuesta
snumpy
Para el navegador moderno, use evento en wheellugar de mousewheel. Referencia: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee
16

Simplemente puede usar el HTML onwheel atributo .

Esta opción no tiene ningún efecto sobre el desplazamiento sobre otros elementos de la página.

Y agregar un oyente para todas las entradas que no funcionan en las entradas creadas dinámicamente posteriormente.

Además, puede eliminar las flechas de entrada con CSS.

input[type="number"]::-webkit-outer-spin-button, 
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
input[type="number"] {
    -moz-appearance: textfield;
}
<input type="number" onwheel="this.blur()" />

Maikon Matheus
fuente
1
¡¡Gracias hermano!! funcionó perfecto en Angular - Material 6
Nasiruddin Saiyed
Podemos encontrar este CSS en muchas fuentes. De todos modos, el CSS es solo una ventaja. La verdadera solución a la pregunta es el atributo HTML onwheel. ;-)
Maikon Matheus
5
¡Me gusta esta solución! Gracias. En mi caso, el onBlur()no fue el esperado. En lugar de eso, configuré un sistema simple return falsepara realmente "no hacer nada en la rueda". <input type="number" onwheel="return false;">
Daniel
14

@Semyon Perepelitsa

Hay una mejor solución para esto. El desenfoque elimina el enfoque de la entrada y ese es un efecto secundario que no desea. En su lugar, debería utilizar evt.preventDefault. Esto evita el comportamiento predeterminado de la entrada cuando el usuario se desplaza. Aquí está el código:

input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })
Dibran
fuente
6
Funciona, pero el evento no burbujeará, por lo que la página no se desplazará. ¿Hay alguna forma de mantener el comportamiento predeterminado (desplazamiento de página) sin difuminar?
GuiGS
Para el navegador moderno, use evento en wheellugar de mousewheel. Referencia: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee
7

Primero debe detener el evento de la rueda del mouse:

  1. Desactivarlo con mousewheel.disableScroll
  2. Interceptarlo con e.preventDefault();
  3. Quitando el foco del elemento el.blur();

Los dos primeros enfoques detienen el desplazamiento de la ventana y el último elimina el foco del elemento; ambos son resultados indeseables.

Una solución es usar el.blur()y volver a enfocar el elemento después de un retraso:

$('input[type=number]').on('mousewheel', function(){
  var el = $(this);
  el.blur();
  setTimeout(function(){
    el.focus();
  }, 10);
});
James EJ
fuente
3
Una solución atractiva, pero en las pruebas descubrí que esta solución tenía el efecto secundario de robar el foco. Modifiqué esto para tener: una prueba para ver si el elemento tenía foco: var hadFocus = el.is(':focus');antes de desenfocar , y luego un guardia para establecer el tiempo de espera solo si hadFocs era verdadero.
Rob Dawson
2

Las respuestas proporcionadas no funcionan en Firefox (Quantum). El detector de eventos debe cambiarse de la rueda del mouse a la rueda:

$(':input[type=number]').on('wheel',function(e){ $(this).blur(); });

Este código funciona en Firefox Quantum y Chrome.

Mathias Bank
fuente
2

Para cualquiera que trabaje con React y busque una solución. Descubrí que la forma más fácil es usar el accesorio onWheelCapture en el componente de entrada como este:

onWheelCapture={e => { e.target.blur() }}

Aleš Chromec
fuente
2

Variación del texto mecanografiado

Typecript necesita saber que está trabajando con un HTMLElement para la seguridad de tipos; de lo contrario, verá muchos Property 'type' does not exist on type 'Element'tipos de errores.

document.addEventListener("mousewheel", function(event){
  let numberInput = (<HTMLInputElement>document.activeElement);
  if (numberInput.type === "number") {
    numberInput.blur();
  }
});
vinilo
fuente
1

Mientras trataba de resolver esto por mí mismo, noté que en realidad es posible retener el desplazamiento de la página y el enfoque de la entrada mientras deshabilita los cambios de número al intentar volver a disparar el evento capturado en el elemento principal del elemento <input type="number"/>en el que se capturó , simplemente así:

e.target.parentElement.dispatchEvent(e);

Sin embargo, esto causa un error en la consola del navegador, y probablemente no se garantiza que funcione en todas partes (solo probé en Firefox), ya que es un código intencionalmente inválido.

Otra solución que funciona bien al menos en Firefox y Chromium es crear temporalmente el <input>elemento readOnly, así:

function handleScroll(e) {
  if (e.target.tagName.toLowerCase() === 'input'
    && (e.target.type === 'number')
    && (e.target === document.activeElement)
    && !e.target.readOnly
  ) {
      e.target.readOnly = true;
      setTimeout(function(el){ el.readOnly = false; }, 0, e.target);
  }
}
document.addEventListener('wheel', function(e){ handleScroll(e); });

Un efecto secundario que he notado es que puede hacer que el campo parpadee durante una fracción de segundo si tiene un estilo diferente para los readOnlycampos, pero al menos en mi caso, esto no parece ser un problema.

De manera similar, (como se explica en la respuesta de James) en lugar de modificar la readOnlypropiedad, puede cambiar blur()el campo y luego focus()regresar, pero nuevamente, dependiendo de los estilos en uso, puede ocurrir algo de parpadeo.

Alternativamente, como se mencionó en otros comentarios aquí, puede simplemente convocar preventDefault()el evento. Suponiendo que solo maneja wheeleventos en entradas numéricas que están enfocadas y bajo el cursor del mouse (eso es lo que significan las tres condiciones anteriores), el impacto negativo en la experiencia del usuario sería casi nulo.

Rimas Kudelis
fuente
1

Si desea una solución que no necesite JavaScript, la combinación de algunas funciones HTML con un pseudoelemento CSS funciona:

span {
  position: relative;
  display: inline-block; /* Fit around contents */
}

span::after {
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0; /* Stretch over containing block */
  cursor: text; /* restore I-beam cursor */
}

/* Restore context menu while editing */
input:focus {
  position: relative;
  z-index: 1;
}
<label>How many javascripts can u fit in u mouth?
  <span><input type="number" min="0" max="99" value="1"></span>
</label>

Esto funciona porque al hacer clic en el contenido de un <label> campo de formulario, se enfocará el campo. Sin embargo, el "panel de ventana" del pseudo-elemento sobre el campo bloqueará los eventos de la rueda del mouse para que no lo alcancen.

El inconveniente es que los botones giratorios arriba / abajo ya no funcionan, pero dijiste que los habías eliminado de todos modos.


En teoría, uno podría restaurar el menú contextual sin requerir que la entrada se enfoque primero: los :hoverestilos no deberían activarse cuando el usuario se desplaza, ya que los navegadores evitan recalcularlos durante el desplazamiento por razones de rendimiento, pero no he cruzado completamente el navegador / dispositivo. probado.

Tigt
fuente
0
function fixNumericScrolling() {
$$( "input[type=number]" ).addEvent( "mousewheel", function(e) {
    stopAll(e);     
} );
}

function stopAll(e) {
if( typeof( e.preventDefault               ) != "undefined" ) e.preventDefault();
if( typeof( e.stopImmediatePropagation     ) != "undefined" ) e.stopImmediatePropagation();
if( typeof( event ) != "undefined" ) {
    if( typeof( event.preventDefault           ) != "undefined" ) event.preventDefault();
    if( typeof( event.stopImmediatePropagation ) != "undefined" ) event.stopImmediatePropagation();
}

return false;
}
syb
fuente
0

La solución más sencilla es agregar la onWheel={ event => event.currentTarget.blur() }}entrada en sí.

TSlegaítis
fuente