Nonaktifkan scrolling pada `<input type = number>`

121

Apakah mungkin untuk menonaktifkan roda gulir mengubah nomor di kolom nomor masukan? Saya telah mengotak-atik CSS khusus webkit untuk menghapus spinner, tetapi saya ingin menyingkirkan perilaku ini sama sekali. Saya suka menggunakan type=numberkarena menampilkan keyboard yang bagus di iOS.

kjs3
sumber
7
gunakan input type tel (type = "tel") daripada menggunakan type = number. Ini akan memunculkan keyboard num iOS.
Praveen Vijayan
Apa yang terjadi jika Anda menambahkan onscrollpenangan dengan hanya event.preventDefault()di dalamnya?
robertc
14
Menurut pendapat saya yang sederhana, saya bahkan tidak berpikir ini harus menjadi fitur. Jika saya memiliki pendapat dalam pengembangan browser, saya mungkin akan mendorong untuk menghapus fitur ini. Itu hanya menjengkelkan, dan saya tidak tahu siapa pun yang benar-benar akan menggunakannya.
Kirkland
3
Saya setuju dengan Anda Kirkland. Hanya UX yang buruk untuk menggulir halaman dengan formulir dan, ketika elemen masukan angka berada di bawah mouse Anda, itu mulai bertambah dan halaman berhenti bergulir. Sangat membingungkan.
kjs3
3
@PraveenVijayan: Meskipun ini adalah solusinya, ini bertentangan dengan alasan apa pun untuk menggunakan jenis input html5 yang baru. Di masa depan, bisa jadi ponsel akan memberi Anda kemungkinan untuk memilih nomor dari kontak atau apa pun, yang akan terlihat sangat aneh jika Anda bermaksud ini menjadi nomor yang berbeda.
kagum pada

Jawaban:

92

Mencegah perilaku default peristiwa roda mouse pada elemen masukan nomor seperti yang disarankan oleh orang lain (memanggil "blur ()" biasanya bukan cara yang disukai untuk melakukannya, karena bukan itu yang diinginkan pengguna).

TAPI. Saya akan menghindari mendengarkan event roda mouse pada semua elemen input-number sepanjang waktu dan hanya melakukannya, ketika elemen berada dalam fokus (saat itulah masalahnya). Jika tidak , pengguna tidak dapat menggulir halaman saat penunjuk mouse berada di mana saja di atas elemen masukan nomor.

Solusi untuk 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')
})

(Delegasikan acara fokus ke elemen formulir di sekitarnya - untuk menghindari banyak pemroses acara, yang berdampak buruk bagi kinerja.)

Grantzau
sumber
2
Jawaban yang bagus. Saya rasa jika saya melakukan ini hari ini, saya akan menggunakan Modernizr.touch untuk menerapkan event listener secara bersyarat pada perangkat non-sentuh. Pada dasarnya apa yang dikatakan pengguna2863715 di bawah ini.
kjs3
Jawaban bagus, tetapi setidaknya di webkit, ini juga mencegah jendela bergulir saat kursor berada di atas elemen masukan. Saya pikir acara roda mouse seharusnya juga menggelembung.
Ryan McGeary
Saat hanya menerapkan fungsi nonaktifkan gulir ke elemen saat berada dalam fokus, ini seharusnya tidak mencegah pengguliran, saat mouse berada di atas elemen masukan. Tapi itu mencegah menggulir jendela, saat elemen berada dalam fokus. Dan ya, mengapa acara roda mouse tidak mendidih ...: /
Grantzau
6
Ini adalah perbaikan yang bagus untuk perilaku yang seharusnya tidak ada sejak awal.
Jonny
Ini tidak berfungsi pada kebanyakan platform tipe unix gnome, osx, android (dengan mouse) karena perilaku scroll tidak memerlukan input untuk difokuskan. Sebagai alternatif, saya hanya menggunakan jenis input teks dan menempatkan batasan nomor saya padanya (kehilangan pintasan tombol atas / bawah tetapi dapat ditambahkan dengan js juga)
zeachco
40
$(document).on("wheel", "input[type=number]", function (e) {
    $(this).blur();
});
stovroz
sumber
2
inilah yang sempurna.
Patrik Laszlo
Ini Bekerja dengan Baik. Terima kasih.
Vijay S
21

Satu pendengar acara untuk mengatur semuanya

Hal ini mirip dengan @ Simon Perepelitsa 's jawaban di js murni, tetapi sedikit lebih sederhana, karena menempatkan salah satu pendengar acara pada elemen dokumen dan memeriksa apakah elemen terfokus adalah masukan nomor:

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

Jika Anda ingin menonaktifkan perilaku pengguliran nilai di beberapa bidang, tetapi tidak yang lain, cukup lakukan ini:

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

dengan ini:

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

Jika sebuah input memiliki kelas noscroll, ia tidak akan berubah saat scroll, jika tidak semuanya tetap sama.

Uji di sini dengan JSFiddle

Peter Rakmanyi
sumber
Saya melihat ini telah direndahkan. Jika Anda melihat masalah, silakan tinggalkan komentar juga dengan downvote. Jika saya melewatkan sesuatu, saya ingin mempelajarinya. Terima kasih.
Peter Rakmanyi
1
Untuk peramban modern, gunakan acara wheelalih-alih mousewheel. Referensi: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event PS. Saya bukan orang yang down vote.
vee
19
input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(event){ this.blur() })

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

Untuk contoh jQuery dan solusi lintas-browser, lihat pertanyaan terkait:

Pemroses peristiwa HTML5 untuk scroll input nomor - khusus Chrome

Simon Perepelitsa
sumber
2
Terima kasih Seymon, saya berhasil melakukannya untuk semua input angka dengan jQuery dengan cara ini: $(':input[type=number]' ).live('mousewheel',function(e){ $(this).blur(); });Saya menggunakan blur alih-alih mencegah default sehingga tidak memblokir halaman dari bergulir!
Thibaut Colson
Tambahan yang bagus tentang blur, saya tidak tahu Anda masih dapat mengizinkan pengguliran halaman. Saya telah memperbarui jawaban saya.
Simon Perepelitsa
13
FYI, live()sudah usang. Sekarang, Anda harus menggunakan on(): $(':input[type=number]').on('mousewheel',function(e){ $(this).blur(); });
Saeid Zebardast
3
@SaeidZebardast Komentar Anda layak untuk dijawab
sombong
Untuk peramban modern, gunakan acara wheelalih-alih mousewheel. Referensi: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee
16

Anda cukup menggunakan atribut onwheel HTML .

Opsi ini tidak berpengaruh pada pengguliran elemen lain dari halaman.

Dan menambahkan pendengar agar semua masukan tidak berfungsi dalam masukan yang dibuat secara dinamis di posterior.

Selain itu, Anda dapat menghapus panah input dengan CSS.

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
sumber
1
Makasih bro !! ini bekerja dengan sempurna di Angular - Material 6
Nasiruddin Saiyed
Kami dapat menemukan CSS ini di banyak sumber. Bagaimanapun juga, CSS hanyalah bonus. Solusi nyata untuk pertanyaan tersebut adalah atribut onwheel HTML. ;-)
Maikon Matheus
5
Saya suka solusi ini! Terima kasih. Dalam kasus saya, onBlur()itu tidak seperti yang diharapkan. Saya menyiapkan cara sederhana return falseuntuk benar-benar "tidak melakukan apa pun di atas roda". <input type="number" onwheel="return false;">
Daniel
14

@Pramuka_semarang

Ada solusi yang lebih baik untuk ini. Blur menghilangkan fokus dari input dan itu adalah efek samping yang tidak Anda inginkan. Anda harus menggunakan evt.preventDefault sebagai gantinya. Ini mencegah perilaku default input saat pengguna menggulir. Ini kodenya:

input = document.getElementById("the_number_input")
input.addEventListener("mousewheel", function(evt){ evt.preventDefault(); })
Dibran
sumber
6
Ini berfungsi, tetapi acara tidak akan menggelembung, jadi halaman tidak akan bergulir. Apakah ada cara untuk mempertahankan perilaku default (gulir halaman) tanpa kabur?
GuiGS
Untuk peramban modern, gunakan acara wheelalih-alih mousewheel. Referensi: developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
vee
7

Pertama, Anda harus menghentikan acara roda mouse dengan:

  1. Menonaktifkannya dengan mousewheel.disableScroll
  2. Mencegat dengan e.preventDefault();
  3. Dengan menghilangkan fokus dari elemen el.blur();

Dua pendekatan pertama menghentikan jendela dari bergulir dan yang terakhir menghapus fokus dari elemen; keduanya merupakan hasil yang tidak diinginkan.

Salah satu solusinya adalah dengan menggunakan el.blur()dan memfokuskan kembali elemen setelah penundaan:

$('input[type=number]').on('mousewheel', function(){
  var el = $(this);
  el.blur();
  setTimeout(function(){
    el.focus();
  }, 10);
});
James EJ
sumber
3
Solusi yang terlihat bagus, tetapi dalam pengujian saya menemukan bahwa solusi ini memiliki efek samping mencuri fokus. Saya men-tweak ini menjadi: tes untuk melihat apakah elemen memiliki fokus: var hadFocus = el.is(':focus');sebelum kabur, dan kemudian penjaga untuk hanya mengatur batas waktu jika hadFocs benar.
Rob Dawson
2

Jawaban yang diberikan tidak berfungsi di Firefox (Quantum). Pemroses acara perlu diubah dari roda mouse ke roda:

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

Kode ini berfungsi di Firefox Quantum dan Chrome.

Bank Mathias
sumber
2

Untuk siapa saja yang bekerja dengan React dan mencari solusi. Saya telah menemukan bahwa cara termudah adalah dengan menggunakan prop onWheelCapture dalam komponen Input seperti ini:

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

Aleš Chromec
sumber
2

Variasi Ketikan

Skrip ketikan perlu tahu bahwa Anda sedang mengerjakan HTMLElement untuk keamanan tipe, jika tidak, Anda akan melihat banyak Property 'type' does not exist on type 'Element'tipe kesalahan.

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

Ketika mencoba menyelesaikan ini untuk diri saya sendiri, saya perhatikan bahwa sebenarnya mungkin untuk mempertahankan pengguliran halaman dan fokus input sambil menonaktifkan perubahan nomor dengan mencoba mengaktifkan kembali peristiwa yang tertangkap pada elemen induk dari yang <input type="number"/>mana itu ditangkap. , seperti ini:

e.target.parentElement.dispatchEvent(e);

Namun, ini menyebabkan kesalahan di konsol browser, dan mungkin tidak dijamin bekerja di mana-mana (saya hanya menguji di Firefox), karena ini adalah kode yang sengaja tidak valid.

Solusi lain yang berfungsi dengan baik setidaknya di Firefox dan Chromium adalah membuat <input>elemen sementara readOnly, seperti ini:

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

Satu efek samping yang saya perhatikan adalah hal itu dapat menyebabkan bidang berkedip selama sepersekian detik jika Anda memiliki gaya berbeda untuk readOnlybidang, tetapi setidaknya untuk kasus saya, ini tampaknya tidak menjadi masalah.

Demikian pula, (seperti yang dijelaskan dalam jawaban James) alih-alih memodifikasi readOnlyproperti, Anda dapat blur()bidang dan kemudian focus()mengembalikannya, tetapi sekali lagi, bergantung pada gaya yang digunakan, beberapa kedipan mungkin terjadi.

Atau, seperti yang disebutkan dalam komentar lain di sini, Anda dapat memanggil preventDefault()acara tersebut sebagai gantinya. Dengan asumsi bahwa Anda hanya menangani wheelkejadian pada masukan angka yang berada dalam fokus dan di bawah kursor mouse (itulah yang ditunjukkan oleh tiga kondisi di atas), dampak negatif pada pengalaman pengguna hampir tidak ada.

Rimas Kudelis
sumber
1

Jika Anda menginginkan solusi yang tidak memerlukan JavaScript, menggabungkan beberapa fungsionalitas HTML dengan pseudo-element CSS akan membantu:

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>

Ini berfungsi karena mengklik konten <label>yang terkait dengan bidang formulir akan memfokuskan bidang tersebut. Namun, "kaca jendela" dari elemen semu di atas bidang akan memblokir peristiwa roda mouse agar tidak mencapainya.

Kekurangannya adalah tombol pemintal atas / bawah tidak lagi berfungsi, tetapi Anda mengatakan telah menghapusnya.


Secara teori, seseorang dapat memulihkan menu konteks tanpa memerlukan input untuk difokuskan terlebih dahulu: :hovergaya tidak boleh diaktifkan saat pengguna menggulir, karena browser menghindari penghitungan ulang selama pengguliran untuk alasan kinerja, tetapi saya belum sepenuhnya lintas-browser / perangkat mengujinya.

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

Solusi termudah adalah menambahkan onWheel={ event => event.currentTarget.blur() }}input itu sendiri.

TSlegaitis
sumber