El evento onchange en tipo de entrada = rango no se activa en Firefox mientras se arrastra
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)">
Aparentemente Chrome y Safari están equivocados: onchange
sólo deberían activarse cuando el usuario suelta el mouse. Para obtener actualizaciones continuas, debes utilizar el oninput
evento, que capturará actualizaciones en vivo en Firefox, Safari y Chrome, tanto desde el mouse como desde el teclado.
Sin embargo, oninput
no 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.
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 r
está su elemento de entrada de rango y f
su 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:
- Pulsación inicial del mouse hacia abajo (o inicio táctil) en la posición actual del control deslizante.
- Pulsación inicial del mouse hacia abajo (o inicio táctil) en una nueva posición del control deslizante.
- cualquier movimiento posterior del mouse (o táctil) después de 1 o 2 a lo largo del control deslizante
- cualquier movimiento posterior del mouse (o táctil) después de 1 o 2 de pasar cualquiera de los extremos del control deslizante
- ú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:
Solución:
La onRangeChange
funció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:
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 onRangeChange
funció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 myRangeInputElmt
está el elemento DOM deseado <input type="range">
y myListener
la 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 event
pará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 input
elemento (por ejemplo, el uso ).removeEventListener
Descripción de la demostración:
En el fragmento de código siguiente, la función onRangeChange
proporciona 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>
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