Deaktivieren Sie das Scrollen auf `<input type = number>`

121

Ist es möglich, das Scrollrad zu deaktivieren, indem die Nummer in einem eingegebenen Nummernfeld geändert wird? Ich habe mit Webkit-spezifischem CSS herumgespielt, um den Spinner zu entfernen, aber ich möchte dieses Verhalten insgesamt beseitigen. Ich benutze type=numberes gerne, da es eine schöne Tastatur unter iOS aufruft.

kjs3
quelle
7
Verwenden Sie den Eingabetyp tel (type = "tel") anstelle von type = number. Es wird eine iOS-Nummerntastatur angezeigt.
Praveen Vijayan
Was passiert, wenn Sie einen onscrollHandler hinzufügen, der nur event.preventDefault()darin enthalten ist?
Robertc
14
Meiner bescheidenen Meinung nach denke ich nicht einmal, dass dies ein Feature sein sollte. Wenn ich bei der Browserentwicklung mitreden könnte, würde ich wahrscheinlich versuchen, diese Funktion zu entfernen. Es ist nichts als nervig und ich kenne niemanden, der es tatsächlich benutzen würde.
Kirkland
3
Ich stimme dir vollkommen zu, Kirkland. Es ist nur schlecht, wenn UX eine Seite mit einem Formular scrollt. Wenn ein Zahleneingabeelement unter der Maus angezeigt wird, wird es inkrementiert und die Seite hört auf zu scrollen. Völlig desorientiert.
kjs3
3
@PraveenVijayan: Obwohl dies eine Problemumgehung ist, widerspricht dies jedem Grund für die Verwendung der neuen HTML5-Eingabetypen. In Zukunft können Telefone Ihnen die Möglichkeit geben, Nummern aus Kontakten oder Ähnlichem auszuwählen. Dies sieht sehr seltsam aus, wenn Sie dies als eine andere Art von Nummer bezeichnen.
Ehrfurcht

Antworten:

92

Verhindern Sie das Standardverhalten des Mausrad-Ereignisses bei Elementen mit Eingabenummer, wie von anderen vorgeschlagen (der Aufruf von "blur ()" ist normalerweise nicht die bevorzugte Methode, da dies nicht den Wünschen des Benutzers entspricht).

ABER. Ich würde es vermeiden, ständig auf alle Elemente der Eingabenummer auf das Mausrad-Ereignis zu warten, und dies nur tun, wenn das Element im Fokus steht (dann besteht das Problem). Andernfalls kann der Benutzer nicht durch die Seite scrollen, wenn sich der Mauszeiger irgendwo über einem Element mit einer eingegebenen Nummer befindet.

Lösung für 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')
})

(Delegieren Sie Fokusereignisse an das umgebende Formularelement, um zu vermeiden, dass viele Ereignis-Listener die Leistung beeinträchtigen.)

Grantzau
quelle
2
Gute Antwort. Ich denke, wenn ich dies heute tun würde, würde ich Modernizr.touch verwenden, um den Ereignis-Listener bedingt auf Nicht-Touch-Geräte anzuwenden. Grundsätzlich, was user2863715 unten sagte.
kjs3
Gute Antwort, aber zumindest im Webkit verhindert dies auch, dass das Fenster gescrollt wird, während sich der Cursor über dem Eingabeelement befindet. Ich dachte, Mausrad-Events sollen auch sprudeln.
Ryan McGeary
Wenn Sie die Funktion zum Deaktivieren des Bildlaufs nur auf ein Element anwenden, wenn es scharfgestellt ist, sollte dies das Scrollen nicht verhindern, wenn sich die Maus über dem Eingabeelement befindet. Es verhindert jedoch das Scrollen im Fenster, wenn das Element scharfgestellt ist. Und ja, warum sprudelt das Mausrad-Ereignis nicht ...: /
Grantzau
6
Dies ist eine nette Lösung für ein Verhalten, das überhaupt nicht existieren sollte.
Jonny
Dies funktioniert auf den meisten Unix-Plattformen wie Gnome, OSX, Android (mit der Maus) nicht, da für das Bildlaufverhalten keine Fokussierung der Eingabe erforderlich ist. Alternativ habe ich nur den Texttyp der Eingaben verwendet und meine Nummernbeschränkung darauf gesetzt (Verlust der Tastenkombination Auf / Ab, kann aber auch mit js hinzugefügt werden)
zeachco
40
$(document).on("wheel", "input[type=number]", function (e) {
    $(this).blur();
});
stovroz
quelle
2
Dies ist derjenige, der perfekt ist.
Patrik Laszlo
Es funktioniert gut. Danke.
Vijay S
20

Ein Ereignis-Listener, der sie alle regiert

Dies ist ähnlich wie @ Simon Perepelitsa ‚s Antwort in reinen js, aber ein bisschen einfacher, als es ein Ereignis - Listener auf dem Dokumentelement und prüft , setzt , wenn das fokussierte Element eine Nummer eingegeben wird:

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

Wenn Sie das Wert-Bildlauf-Verhalten für einige Felder deaktivieren möchten, für andere jedoch nicht, tun Sie stattdessen Folgendes:

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

mit diesem:

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

Wenn eine Eingabe die Noscroll-Klasse hat, ändert sie sich beim Scrollen nicht, andernfalls bleibt alles beim Alten.

Testen Sie hier mit JSFiddle

Peter Rakmanyi
quelle
Ich sehe, dass dies abgelehnt wurde. Wenn Sie ein Problem sehen, hinterlassen Sie bitte auch einen Kommentar mit der Abwertung. Wenn ich etwas verpasst habe, würde ich gerne lernen, was es ist. Vielen Dank.
Peter Rakmanyi
1
Für moderne Browser verwenden Sie bitte event wheelanstelle von mousewheel. Referenz: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event PS. Ich bin nicht derjenige, der abstimmt.
Vee
19
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

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

Ein jQuery-Beispiel und eine browserübergreifende Lösung finden Sie in der zugehörigen Frage:

HTML5-Ereignis-Listener für die Eingabe von Zahlen - nur Chrome

Simon Perepelitsa
quelle
2
Dank Seymon habe ich es für alle Zahleneingaben mit jQuery folgendermaßen geschafft: $(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });Ich habe Unschärfe verwendet, anstatt die Standardeinstellung zu verhindern, damit die Seite nicht gescrollt wird!
Thibaut Colson
Eine nette Ergänzung zu Unschärfe. Ich wusste nicht, dass Sie das Scrollen von Seiten weiterhin zulassen können. Ich habe meine Antwort aktualisiert.
Simon Perepelitsa
13
Zu Ihrer Information, live()ist veraltet. Jetzt sollten Sie verwenden on(): $(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
Saeid Zebardast
3
@SaeidZebardast Ihr Kommentar verdient eine Antwort
snumpy
Für moderne Browser verwenden Sie bitte event wheelanstelle von mousewheel. Referenz: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
siehe
16

Sie können einfach das HTML- Onwheel- Attribut verwenden.

Diese Option hat keine Auswirkungen auf das Scrollen über andere Elemente der Seite.

Und fügen Sie einen Listener für alle Eingaben hinzu, die bei dynamisch nachträglich erstellten Eingaben nicht funktionieren.

Zusätzlich können Sie die Eingabepfeile mit CSS entfernen.

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
quelle
1
Dank bro!! es funktionierte perfekt in Angular - Material 6
Nasiruddin Saiyed
Wir können dieses CSS in vielen Quellen finden. Auf jeden Fall ist das CSS nur ein Bonus. Die eigentliche Lösung für die Frage ist das HTML-Onwheel-Attribut. ;-)
Maikon Matheus
5
Ich mag diese Lösung! Vielen Dank. In meinem Fall war das onBlur()nicht wie erwartet. Ich richte return falsestattdessen ein einfaches ein, um wirklich "nichts auf dem Rad zu tun". <input type="number" onwheel="return false;">
Daniel
14

@ Semyon Perepelitsa

Dafür gibt es eine bessere Lösung. Unschärfe entfernt den Fokus von der Eingabe und das ist ein Nebeneffekt, den Sie nicht wollen. Sie sollten stattdessen evt.preventDefault verwenden. Dies verhindert das Standardverhalten der Eingabe beim Scrollen des Benutzers. Hier ist der Code:

input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })
Dibran
quelle
6
Es funktioniert, aber das Ereignis sprudelt nicht, sodass die Seite nicht gescrollt wird. Gibt es eine Möglichkeit, das Standardverhalten (Seitenlauf) beizubehalten, ohne zu verwischen?
GuiGS
Für moderne Browser verwenden Sie bitte event wheelanstelle von mousewheel. Referenz: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
siehe
7

Zuerst müssen Sie das Mausrad-Ereignis stoppen, indem Sie entweder:

  1. Deaktivieren mit mousewheel.disableScroll
  2. Abfangen mit e.preventDefault();
  3. Durch Entfernen des Fokus vom Element el.blur();

Die ersten beiden Ansätze verhindern das Scrollen des Fensters und der letzte entfernt den Fokus vom Element. Beides sind unerwünschte Ergebnisse.

Eine Problemumgehung besteht darin el.blur(), das Element nach einer Verzögerung zu verwenden und neu zu fokussieren:

$('input[type=number]').on('mousewheel', function(){
  var el = $(this);
  el.blur();
  setTimeout(function(){
    el.focus();
  }, 10);
});
James EJ
quelle
3
Eine gut aussehende Lösung, aber beim Testen stellte ich fest, dass diese Lösung den Nebeneffekt hatte, den Fokus zu stehlen. Ich habe dies so angepasst, dass: ein Test, um var hadFocus = el.is(':focus');festzustellen, ob das Element den Fokus hatte: vor dem Verwischen, und dann ein Schutz, um das Zeitlimit nur festzulegen, wenn hadFocs wahr ist.
Rob Dawson
2

Die angegebenen Antworten funktionieren in Firefox (Quantum) nicht. Der Ereignis-Listener muss vom Mausrad zum Rad gewechselt werden:

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

Dieser Code funktioniert unter Firefox Quantum und Chrome.

Mathias Bank
quelle
2

Für alle, die mit React arbeiten und nach einer Lösung suchen. Ich habe herausgefunden, dass der einfachste Weg darin besteht, die onWheelCapture-Requisite in der Eingabekomponente wie folgt zu verwenden:

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

Aleš Chromec
quelle
2

Typoskript-Variation

Typescript muss wissen, dass Sie aus Gründen der Typensicherheit mit einem HTMLElement arbeiten. Andernfalls werden viele Property 'type' does not exist on type 'Element'Arten von Fehlern angezeigt .

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

Beim Versuch, dies für mich selbst zu lösen, habe ich festgestellt, dass es tatsächlich möglich ist, das Scrollen der Seite und den Fokus der Eingabe beizubehalten, während Nummernänderungen deaktiviert werden, indem versucht wird, das abgefangene Ereignis auf dem übergeordneten Element des abgefangenen Elements <input type="number"/>erneut auszulösen einfach so:

e.target.parentElement.dispatchEvent(e);

Dies führt jedoch zu einem Fehler in der Browserkonsole und funktioniert wahrscheinlich nicht überall (ich habe nur auf Firefox getestet), da es sich absichtlich um ungültigen Code handelt.

Eine andere Lösung, die zumindest unter Firefox und Chrom gut funktioniert, besteht darin, das <input>Element vorübergehend readOnlywie folgt zu erstellen :

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); });

Ein Nebeneffekt, den ich bemerkt habe, ist, dass das Feld möglicherweise für den Bruchteil einer Sekunde flackert, wenn Sie ein anderes Styling für readOnlyFelder haben, aber zumindest für meinen Fall scheint dies kein Problem zu sein.

In ähnlicher Weise können Sie (wie in James 'Antwort erläutert), anstatt die readOnlyEigenschaft zu ändern , blur()das Feld und dann focus()wieder zurück, aber abhängig von den verwendeten Stilen kann es erneut zu Flackern kommen.

Alternativ können Sie, wie in anderen Kommentaren hier erwähnt, preventDefault()stattdessen einfach die Veranstaltung aufrufen . Angenommen, Sie behandeln wheelEreignisse nur an Zahleneingaben, die im Fokus und unter dem Mauszeiger stehen (das bedeuten die drei oben genannten Bedingungen), dann wären die negativen Auswirkungen auf die Benutzererfahrung nahezu gleich Null.

Rimas Kudelis
quelle
1

Wenn Sie eine Lösung suchen, die kein JavaScript benötigt, reicht die Kombination einiger HTML-Funktionen mit einem CSS-Pseudoelement aus:

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>

Dies funktioniert, weil durch Klicken auf den Inhalt <label>eines Felds, das einem Formularfeld zugeordnet ist, das Feld fokussiert wird. Die „Fensterscheibe“ des Pseudoelements über dem Feld verhindert jedoch, dass Mausradereignisse es erreichen.

Der Nachteil ist, dass die Auf- / Ab-Drehknöpfe nicht mehr funktionieren, aber Sie sagten, Sie hätten diese trotzdem entfernt.


Theoretisch könnte man das Kontextmenü wiederherstellen, ohne dass die Eingabe zuerst fokussiert werden muss: :hoverStile sollten nicht ausgelöst werden, wenn der Benutzer einen Bildlauf durchführt, da Browser es aus Leistungsgründen vermeiden, sie während des Bildlaufs neu zu berechnen, aber ich habe Browser / Gerät nicht gründlich übergreifend habe es getestet.

Tigt
quelle
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
quelle
0

Die einfachste Lösung besteht darin, die onWheel={ event => event.currentTarget.blur() }}Eingabe selbst hinzuzufügen .

TSlegaitis
quelle