RÉSUMÉ:
Je fournis ici une capacité de bureau et mobile multi-navigateur sans jQuery pour répondre de manière cohérente aux interactions plage / curseur, ce qui n'est pas possible dans les navigateurs actuels. Il oblige essentiellement tous les navigateurs à émuler l' on("change"...
événement IE11 pour leur on("change"...
ou leurs on("input"...
événements. La nouvelle fonction est ...
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);});
}
... où r
est votre élément d'entrée de plage et f
votre auditeur. L'auditeur sera appelé après toute interaction qui modifie la valeur de la plage / du curseur, mais pas après les interactions qui ne modifient pas cette valeur, y compris les interactions initiales de la souris ou du toucher à la position actuelle du curseur ou lors du déplacement de l'une ou l'autre extrémité du curseur.
Problème:
Au début de juin 2016, les différents navigateurs diffèrent en termes de réponse à l'utilisation de la plage / du curseur. Cinq scénarios sont pertinents:
- initial de la souris (ou démarrage tactile) à la position actuelle du curseur
- déplacement initial de la souris (ou démarrage tactile) à une nouvelle position du curseur
- tout mouvement ultérieur de la souris (ou du toucher) après 1 ou 2 le long du curseur
- tout mouvement ultérieur de la souris (ou du toucher) après 1 ou 2 après chaque extrémité du curseur
- souris finale (ou tactile)
Le tableau suivant montre comment au moins trois navigateurs de bureau différents diffèrent dans leur comportement en ce qui concerne les scénarios ci-dessus auxquels ils répondent:
Solution:
La onRangeChange
fonction fournit une réponse inter-navigateur cohérente et prévisible aux interactions plage / curseur. Il oblige tous les navigateurs à se comporter conformément au tableau suivant:
Dans IE11, le code permet essentiellement à tout de fonctionner selon le statu quo, c'est-à-dire qu'il permet à l' "change"
événement de fonctionner de manière standard et que l' "input"
événement n'a pas d'importance car il ne se déclenche jamais de toute façon. Dans d'autres navigateurs, l' "change"
événement est effectivement réduit au silence (pour empêcher le déclenchement d'événements supplémentaires et parfois non apparents). De plus, l' "input"
événement ne déclenche son écouteur que lorsque la valeur de la plage / du curseur change. Pour certains navigateurs (par exemple Firefox), cela se produit car l'auditeur est effectivement désactivé dans les scénarios 1, 4 et 5 de la liste ci-dessus.
(Si vous avez vraiment besoin qu'un écouteur soit activé dans les scénarios 1, 4 et / ou 5, vous pouvez essayer d'incorporer les événements "mousedown"
/ "touchstart"
, "mousemove"
/ "touchmove"
et / ou "mouseup"
/ "touchend"
. Une telle solution dépasse le cadre de cette réponse.)
Fonctionnalité dans les navigateurs mobiles:
J'ai testé ce code dans les navigateurs de bureau mais pas dans les navigateurs mobiles. Cependant, dans une autre réponse sur cette page, MBourne a montré que ma solution ici "... semble fonctionner dans tous les navigateurs que j'ai pu trouver (bureau Win: IE, Chrome, Opera, FF; Android Chrome, Opera et FF, iOS Safari) " . (Merci MBourne.)
Usage:
Pour utiliser cette solution, incluez la onRangeChange
fonction du résumé ci-dessus (simplifiée / minifiée) ou l'extrait de code de démonstration ci-dessous (fonctionnellement identique mais plus explicite) dans votre propre code. Appelez-le comme suit:
onRangeChange(myRangeInputElmt, myListener);
où myRangeInputElmt
est votre <input type="range">
élément DOM souhaité et myListener
est la fonction d'écoute / gestionnaire que vous souhaitez invoquer lors d' "change"
événements similaires.
Votre auditeur peut être sans paramètre si vous le souhaitez ou peut utiliser le event
paramètre, c'est-à-dire que l'un des éléments suivants fonctionnerait, selon vos besoins:
var myListener = function() {...
ou
var myListener = function(evt) {...
(La suppression de l'écouteur d'événements de l' input
élément (par exemple en utilisant removeEventListener
) n'est pas traitée dans cette réponse.)
Description de la démonstration:
Dans l'extrait de code ci-dessous, la fonction onRangeChange
fournit la solution universelle. Le reste du code est simplement un exemple pour démontrer son utilisation. Toute variable qui commence par my...
n'est pas pertinente pour la solution universelle et n'est présente que pour la démonstration.
La démonstration montre la plage / valeur du curseur ainsi que le nombre de fois la norme "change"
, "input"
et sur mesure des "onRangeChange"
événements ont tiré (lignes A, B et C respectivement). Lorsque vous exécutez cet extrait dans différents navigateurs, notez les points suivants lorsque vous interagissez avec la plage / le curseur:
- Dans IE11, les valeurs des lignes A et C changent toutes les deux dans les scénarios 2 et 3 ci-dessus tandis que la ligne B ne change jamais.
- Dans Chrome et Safari, les valeurs des lignes B et C changent toutes les deux dans les scénarios 2 et 3 tandis que la ligne A change uniquement pour le scénario 5.
- Dans Firefox, la valeur de la ligne A ne change que pour le scénario 5, la ligne B change pour les cinq scénarios et la ligne C ne change que pour les scénarios 2 et 3.
- Dans tous les navigateurs ci-dessus, les modifications de la ligne C (la solution proposée) sont identiques, c'est-à-dire uniquement pour les scénarios 2 et 3.
Code de démonstration:
// 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édit:
Bien que l'implémentation ici soit largement la mienne, elle a été inspirée par la réponse de MBourne . Cette autre réponse suggérait que les événements «entrée» et «changement» pouvaient être fusionnés et que le code résultant fonctionnerait à la fois sur les navigateurs de bureau et mobiles. Cependant, le code dans cette réponse entraîne le déclenchement d'événements "supplémentaires" cachés, ce qui en soi est problématique, et les événements déclenchés diffèrent entre les navigateurs, un autre problème. Ma mise en œuvre ici résout ces problèmes.
Mots clés:
Événements du curseur de plage de type d'entrée JavaScript changer la compatibilité du navigateur d'entrée cross-browser desktop mobile no-jQuery
onchange
ne se déclenche pas. C'est en résolvant ce problème que j'ai trouvé cette question.