ZUSAMMENFASSUNG:
Ich biete hier eine browserfreie Desktop- und Mobilfunktion ohne jQuery, um konsistent auf Interaktionen zwischen Bereich und Schieberegler zu reagieren, was in aktuellen Browsern nicht möglich ist. Es zwingt im Wesentlichen alle Browser, das IE11- on("change"...
Ereignis entweder für ihre on("change"...
oder für on("input"...
Ereignisse zu emulieren . Die neue Funktion ist ...
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);});
}
... wo r
ist Ihr Bereichseingabeelement und wo f
ist Ihr Listener? Der Listener wird nach jeder Interaktion aufgerufen, die den Bereich / Schiebereglerwert ändert, jedoch nicht nach Interaktionen, die diesen Wert nicht ändern, einschließlich anfänglicher Maus- oder Berührungsinteraktionen an der aktuellen Schiebereglerposition oder beim Verlassen eines Schiebereglers.
Problem:
Ab Anfang Juni 2016 unterscheiden sich verschiedene Browser hinsichtlich ihrer Reaktion auf die Verwendung von Bereichen / Schiebereglern. Fünf Szenarien sind relevant:
- anfängliches Mouse-Down (oder Touch-Start) an der aktuellen Schiebereglerposition
- anfängliches Mouse-Down (oder Touch-Start) an einer neuen Schiebereglerposition
- Jede nachfolgende Mausbewegung (oder Berührungsbewegung) nach 1 oder 2 entlang des Schiebereglers
- Jede nachfolgende Mausbewegung (oder Berührungsbewegung) nach 1 oder 2 nach einem Ende des Schiebereglers
- endgültiges Mouse-Up (oder Touch-End)
Die folgende Tabelle zeigt, wie sich mindestens drei verschiedene Desktop-Browser in Bezug auf das oben genannte Szenario in ihrem Verhalten unterscheiden:
Lösung:
Die onRangeChange
Funktion bietet eine konsistente und vorhersehbare browserübergreifende Reaktion auf Interaktionen zwischen Bereich und Schieberegler. Es zwingt alle Browser, sich gemäß der folgenden Tabelle zu verhalten:
In IE11 erlaubt der Code im Wesentlichen, dass alles gemäß dem Status Quo "change"
funktioniert , dh, dass das Ereignis auf seine Standardweise funktioniert und das "input"
Ereignis irrelevant ist, da es sowieso nie ausgelöst wird. In anderen Browsern wird das "change"
Ereignis effektiv stummgeschaltet (um zu verhindern, dass zusätzliche und manchmal nicht leicht erkennbare Ereignisse ausgelöst werden). Darüber hinaus löst das "input"
Ereignis seinen Listener nur aus, wenn sich der Wert des Bereichs / Schiebereglers ändert. Bei einigen Browsern (z. B. Firefox) tritt dies auf, weil der Listener in den Szenarien 1, 4 und 5 aus der obigen Liste effektiv stummgeschaltet ist.
(Wenn Sie wirklich benötigen, dass ein Listener in Szenario 1, 4 und / oder 5 aktiviert wird, können Sie versuchen, "mousedown"
/ "touchstart"
, "mousemove"
/ "touchmove"
und / oder "mouseup"
/ "touchend"
Ereignisse einzubeziehen. Eine solche Lösung würde den Rahmen dieser Antwort sprengen.)
Funktionalität in mobilen Browsern:
Ich habe diesen Code in Desktop-Browsern getestet, aber nicht in mobilen Browsern. In einer anderen Antwort auf dieser Seite hat MBourne jedoch gezeigt, dass meine Lösung hier "... in jedem Browser zu funktionieren scheint, den ich finden konnte (Win-Desktop: IE, Chrome, Opera, FF; Android Chrome, Opera und FF, iOS Safari). " . (Danke MBourne.)
Verwendung:
Um diese Lösung zu verwenden, onRangeChange
fügen Sie die Funktion aus der obigen Zusammenfassung (vereinfacht / minimiert) oder das Demo-Code-Snippet unten (funktional identisch, aber selbsterklärender) in Ihren eigenen Code ein. Rufen Sie es wie folgt auf:
onRangeChange(myRangeInputElmt, myListener);
Wo myRangeInputElmt
ist Ihr gewünschtes <input type="range">
DOM-Element und welche myListener
Listener / Handler-Funktion möchten Sie bei "change"
ähnlichen Ereignissen aufrufen ?
Ihr Listener kann auf Wunsch parameterlos sein oder den event
Parameter verwenden, dh je nach Ihren Anforderungen funktioniert eine der folgenden Möglichkeiten :
var myListener = function() {...
oder
var myListener = function(evt) {...
(Das Entfernen des Ereignis-Listeners aus dem input
Element (z. B. Verwenden von removeEventListener
) wird in dieser Antwort nicht behandelt.)
Demo Beschreibung:
Im folgenden Codeausschnitt bietet die Funktion onRangeChange
die universelle Lösung. Der Rest des Codes ist lediglich ein Beispiel, um seine Verwendung zu demonstrieren. Jede Variable, die mit beginnt, my...
ist für die universelle Lösung irrelevant und nur für die Demo vorhanden.
Die Demo zeigt den Bereich / Reglerwert sowie die Anzahl , wie oft den Standard "change"
, "input"
und benutzerdefinierte "onRangeChange"
Ereignisse ausgelöst hat (Zeilen A, B und C jeweils). Beachten Sie beim Ausführen dieses Snippets in verschiedenen Browsern Folgendes, wenn Sie mit dem Bereich / Schieberegler interagieren:
- In IE11 ändern sich die Werte in den Zeilen A und C in den obigen Szenarien 2 und 3, während sich die Zeile B nie ändert.
- In Chrome und Safari ändern sich die Werte in den Zeilen B und C in Szenario 2 und 3, während sich Zeile A nur für Szenario 5 ändert.
- In Firefox ändert sich der Wert in Zeile A nur für Szenario 5, Zeile B für alle fünf Szenarien und Zeile C nur für Szenario 2 und 3.
- In allen oben genannten Browsern sind die Änderungen in Zeile C (der vorgeschlagenen Lösung) identisch, dh nur für die Szenarien 2 und 3.
Demo-Code:
// 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>
Anerkennung:
Während die Implementierung hier größtenteils meine eigene ist, wurde sie von MBournes Antwort inspiriert . Diese andere Antwort deutete darauf hin, dass die Ereignisse "Eingabe" und "Änderung" zusammengeführt werden könnten und der resultierende Code sowohl in Desktop- als auch in mobilen Browsern funktionieren würde. Der Code in dieser Antwort führt jedoch dazu, dass versteckte "zusätzliche" Ereignisse ausgelöst werden, was an und für sich problematisch ist, und die ausgelösten Ereignisse unterscheiden sich zwischen den Browsern, ein weiteres Problem. Meine Implementierung hier löst diese Probleme.
Schlüsselwörter:
Die Schiebereglerereignisse für den JavaScript-Eingabetyp ändern die Kompatibilität des Eingabebrowsers für browserübergreifende Desktop-Mobilgeräte ohne jQuery
onchange
feuert der nicht. Bei der Fehlerbehebung dieses Problems habe ich diese Frage gefunden.