El evento onchange en tipo de entrada = rango no se activa en Firefox mientras se arrastra

Resuelto Prasanth K C asked hace 11 años • 10 respuestas

Cuando jugué con <input type="range">, Firefox activa un evento de cambio solo si soltamos el control deslizante a una nueva posición donde Chrome y otros activan eventos de cambio mientras se arrastra el control deslizante.

¿Cómo puedo hacer que esto suceda al arrastrar en Firefox?

function showVal(newVal){
    document.getElementById("valBox").innerHTML=newVal;
}
<span id="valBox"></span>
<input type="range" min="5" max="10" step="1" onchange="showVal(this.value)">
Expandir fragmento

Prasanth K C avatar Aug 31 '13 12:08 Prasanth K C
Aceptado

Aparentemente Chrome y Safari están equivocados: onchangesólo deberían activarse cuando el usuario suelta el mouse. Para obtener actualizaciones continuas, debes utilizar el oninputevento, que capturará actualizaciones en vivo en Firefox, Safari y Chrome, tanto desde el mouse como desde el teclado.

Sin embargo, oninputno es compatible con IE10, por lo que lo mejor es combinar los dos controladores de eventos, de esta manera:

<span id="valBox"></span>
<input
  type="range"
  min="5"
  max="10"
  step="1"
  oninput="showVal(this.value)"
  onchange="showVal(this.value)"
/>

Consulte este hilo de Bugzilla para obtener más información.

Frederik avatar Sep 28 '2013 13:09 Frederik

RESUMEN:

Proporciono aquí una capacidad de escritorio y móvil sin jQuery para varios navegadores para responder consistentemente a las interacciones de rango/control deslizante, algo que no es posible en los navegadores actuales. Básicamente, obliga a todos los navegadores a emular on("change"...el evento de IE11 para sus on("change"...eventos on("input".... La nueva función es...

function onRangeChange(r,f) {
  var n,c,m;
  r.addEventListener("input",function(e){n=1;c=e.target.value;if(c!=m)f(e);m=c;});
  r.addEventListener("change",function(e){if(!n)f(e);});
}

... ¿dónde restá su elemento de entrada de rango y fsu oyente? Se llamará al oyente después de cualquier interacción que cambie el valor del rango/control deslizante, pero no después de interacciones que no cambien ese valor, incluidas las interacciones iniciales del mouse o táctiles en la posición actual del control deslizante o al moverse fuera de cualquiera de los extremos del control deslizante.

Problema:

A principios de junio de 2016, los diferentes navegadores difieren en términos de cómo responden al uso del rango/control deslizante. Cinco escenarios son relevantes:

  1. Pulsación inicial del mouse hacia abajo (o inicio táctil) en la posición actual del control deslizante.
  2. Pulsación inicial del mouse hacia abajo (o inicio táctil) en una nueva posición del control deslizante.
  3. cualquier movimiento posterior del mouse (o táctil) después de 1 o 2 a lo largo del control deslizante
  4. cualquier movimiento posterior del mouse (o táctil) después de 1 o 2 de pasar cualquiera de los extremos del control deslizante
  5. último movimiento del mouse hacia arriba (o toque final)

La siguiente tabla muestra cómo al menos tres navegadores de escritorio diferentes difieren en su comportamiento con respecto a cuál de los escenarios anteriores responden:

tabla que muestra las diferencias del navegador con respecto a qué eventos responden y cuándo

Solución:

La onRangeChangefunción proporciona una respuesta consistente y predecible en todos los navegadores a las interacciones de rango/control deslizante. Obliga a todos los navegadores a comportarse según la siguiente tabla:

tabla que muestra el comportamiento de todos los navegadores que utilizan la solución propuesta

En IE11, el código esencialmente permite que todo funcione según el status quo, es decir, permite que el "change"evento funcione de forma estándar y el "input"evento es irrelevante ya que de todos modos nunca se activa. En otros navegadores, el "change"evento se silencia de manera efectiva (para evitar que se activen eventos adicionales y, a veces, no evidentes). Además, el "input"evento activa su oyente solo cuando cambia el valor del rango/control deslizante. Para algunos navegadores (por ejemplo, Firefox), esto ocurre porque el oyente se silencia de manera efectiva en los escenarios 1, 4 y 5 de la lista anterior.

(Si realmente necesita que se active un oyente en cualquiera de los escenarios 1, 4 y/o 5, puede intentar incorporar "mousedown"/ "touchstart", "mousemove"/ "touchmove"y/o "mouseup"/ "touchend"eventos. Dicha solución está más allá del alcance de esta respuesta).

Funcionalidad en navegadores móviles:

He probado este código en navegadores de escritorio, pero no en ningún navegador móvil. Sin embargo, en otra respuesta en esta página, MBourne ha demostrado que mi solución aquí "... parece funcionar en todos los navegadores que pude encontrar (Win escritorio: IE, Chrome, Opera, FF; Android Chrome, Opera y FF, iOS Safari) " . (Gracias MBourne.)

Uso:

Para utilizar esta solución, incluya la onRangeChangefunción del resumen anterior (simplificado/minimizado) o el fragmento de código de demostración a continuación (funcionalmente idéntico pero más explicativo) en su propio código. Invocarlo de la siguiente manera:

onRangeChange(myRangeInputElmt, myListener);

¿Dónde myRangeInputElmtestá el elemento DOM deseado <input type="range">y myListenerla función de escucha/controlador que desea invocar en "change"eventos similares?

Su oyente puede no tener parámetros si lo desea o puede usar el eventparámetro, es decir, cualquiera de las siguientes opciones funcionaría, dependiendo de sus necesidades:

var myListener = function() {...

o

var myListener = function(evt) {...

( En esta respuesta no se aborda la eliminación del detector de eventos del inputelemento (por ejemplo, el uso ).removeEventListener

Descripción de la demostración:

En el fragmento de código siguiente, la función onRangeChangeproporciona la solución universal. El resto del código es simplemente un ejemplo para demostrar su uso. Cualquier variable que comience con my...es irrelevante para la solución universal y solo está presente por el bien de la demostración.

"change"La demostración muestra el valor del rango/control deslizante , así como el número de veces que se han activado los eventos estándar "input"y personalizados (filas A, B y C respectivamente). "onRangeChange"Al ejecutar este fragmento en diferentes navegadores, tenga en cuenta lo siguiente al interactuar con el rango/control deslizante:

  • En IE11, los valores de las filas A y C cambian en los escenarios 2 y 3 anteriores, mientras que la fila B nunca cambia.
  • En Chrome y Safari, los valores de las filas B y C cambian en los escenarios 2 y 3, mientras que la fila A cambia solo en el escenario 5.
  • En Firefox, el valor de la fila A cambia solo para el escenario 5, la fila B cambia para los cinco escenarios y la fila C cambia solo para los escenarios 2 y 3.
  • En todos los navegadores anteriores, los cambios en la fila C (la solución propuesta) son idénticos, es decir, sólo para los escenarios 2 y 3.

Código de demostración:

// main function for emulating IE11's "change" event:

function onRangeChange(rangeInputElmt, listener) {

  var inputEvtHasNeverFired = true;

  var rangeValue = {current: undefined, mostRecent: undefined};
  
  rangeInputElmt.addEventListener("input", function(evt) {
    inputEvtHasNeverFired = false;
    rangeValue.current = evt.target.value;
    if (rangeValue.current !== rangeValue.mostRecent) {
      listener(evt);
    }
    rangeValue.mostRecent = rangeValue.current;
  });

  rangeInputElmt.addEventListener("change", function(evt) {
    if (inputEvtHasNeverFired) {
      listener(evt);
    }
  }); 

}

// example usage:

var myRangeInputElmt = document.querySelector("input"          );
var myRangeValPar    = document.querySelector("#rangeValPar"   );
var myNumChgEvtsCell = document.querySelector("#numChgEvtsCell");
var myNumInpEvtsCell = document.querySelector("#numInpEvtsCell");
var myNumCusEvtsCell = document.querySelector("#numCusEvtsCell");

var myNumEvts = {input: 0, change: 0, custom: 0};

var myUpdate = function() {
  myNumChgEvtsCell.innerHTML = myNumEvts["change"];
  myNumInpEvtsCell.innerHTML = myNumEvts["input" ];
  myNumCusEvtsCell.innerHTML = myNumEvts["custom"];
};

["input", "change"].forEach(function(myEvtType) {
  myRangeInputElmt.addEventListener(myEvtType,  function() {
    myNumEvts[myEvtType] += 1;
    myUpdate();
  });
});

var myListener = function(myEvt) {
  myNumEvts["custom"] += 1;
  myRangeValPar.innerHTML = "range value: " + myEvt.target.value;
  myUpdate();
};

onRangeChange(myRangeInputElmt, myListener);
table {
  border-collapse: collapse;  
}
th, td {
  text-align: left;
  border: solid black 1px;
  padding: 5px 15px;
}
<input type="range"/>
<p id="rangeValPar">range value: 50</p>
<table>
  <tr><th>row</th><th>event type                     </th><th>number of events    </th><tr>
  <tr><td>A</td><td>standard "change" events         </td><td id="numChgEvtsCell">0</td></tr>
  <tr><td>B</td><td>standard "input" events          </td><td id="numInpEvtsCell">0</td></tr>
  <tr><td>C</td><td>new custom "onRangeChange" events</td><td id="numCusEvtsCell">0</td></tr>
</table>
Expandir fragmento

Crédito:

Si bien la implementación aquí es en gran medida mía, se inspiró en la respuesta de MBourne . Esa otra respuesta sugirió que los eventos de "entrada" y "cambio" podrían fusionarse y que el código resultante funcionaría tanto en navegadores de escritorio como móviles. Sin embargo, el código en esa respuesta da como resultado que se activen eventos "adicionales" ocultos, lo que en sí mismo es problemático, y los eventos activados difieren entre los navegadores, un problema adicional. Mi implementación aquí resuelve esos problemas.

Palabras clave:

Los eventos del control deslizante del rango de tipo de entrada de JavaScript cambian la entrada Compatibilidad del navegador entre navegadores escritorio móvil sin jQuery

Andrew Willems avatar Jun 03 '2016 21:06 Andrew Willems