RINGKASAN:
Saya berikan di sini kemampuan lintas-peramban desktop dan seluler tanpa jQuery untuk secara konsisten merespons interaksi rentang / penggeser, sesuatu yang tidak mungkin dilakukan di peramban saat ini. Ini pada dasarnya memaksa semua browser untuk meniru on("change"...
acara IE11 untuk mereka on("change"...
atau on("input"...
acara. Fungsi baru adalah ...
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);});
}
... di mana r
elemen input rentang Anda dan f
pendengar Anda. Pendengar akan dipanggil setelah interaksi apa pun yang mengubah nilai rentang / penggeser tetapi tidak setelah interaksi yang tidak mengubah nilai itu, termasuk interaksi awal mouse atau sentuh pada posisi penggeser saat ini atau saat memindahkan salah satu ujung penggeser.
Masalah:
Pada awal Juni 2016, berbagai browser berbeda dalam hal bagaimana mereka merespons penggunaan rentang / slider. Lima skenario relevan:
- mouse-down awal (atau sentuh-start) pada posisi slider saat ini
- mouse-down awal (atau sentuh-start) pada posisi slider baru
- gerakan mouse berikutnya (atau sentuh) setelah 1 atau 2 sepanjang slider
- gerakan mouse berikutnya (atau sentuh) setelah 1 atau 2 melewati salah satu ujung slider
- mouse-up akhir (atau touch-end)
Tabel berikut menunjukkan bagaimana setidaknya tiga browser desktop berbeda dalam perilaku mereka sehubungan dengan skenario di atas yang mereka respons:
Larutan:
The onRangeChange
berfungsi memberikan respon lintas-browser konsisten dan dapat diprediksi interaksi berbagai / slider. Itu memaksa semua browser untuk berperilaku sesuai dengan tabel berikut:
Di IE11, kode ini pada dasarnya memungkinkan semuanya beroperasi sesuai status quo, yaitu memungkinkan "change"
acara berfungsi dengan cara standar dan "input"
acara tidak relevan karena tidak pernah menyala. Di browser lain, "change"
acara secara efektif dibungkam (untuk mencegah peristiwa tambahan dan kadang-kadang tidak mudah-muncul dari penembakan). Selain itu, "input"
acara ini hanya akan mengaktifkan pendengar ketika nilai rentang / penggeser berubah. Untuk beberapa browser (misalnya Firefox) ini terjadi karena pendengar secara efektif dibungkam dalam skenario 1, 4 dan 5 dari daftar di atas.
(Jika Anda benar-benar membutuhkan pendengar untuk diaktifkan dalam skenario 1, 4 dan / atau 5 Anda dapat mencoba memasukkan "mousedown"
/ "touchstart"
, "mousemove"
/ "touchmove"
dan / atau "mouseup"
/ "touchend"
peristiwa. Solusi semacam itu berada di luar cakupan jawaban ini.)
Fungsi di Peramban Seluler:
Saya telah menguji kode ini di peramban desktop tetapi tidak di peramban seluler mana pun. Namun, dalam jawaban lain di halaman ini MBourne telah menunjukkan bahwa solusi saya di sini "... tampaknya berfungsi di setiap browser yang dapat saya temukan (Menangkan desktop: IE, Chrome, Opera, FF; Android Chrome, Opera dan FF, Safari Safari) " . (Terima kasih MBourne.)
Pemakaian:
Untuk menggunakan solusi ini, sertakan onRangeChange
fungsi dari ringkasan di atas (disederhanakan / diperkecil) atau cuplikan kode demo di bawah ini (identik secara fungsional tetapi lebih jelas) dalam kode Anda sendiri. Aktifkan sebagai berikut:
onRangeChange(myRangeInputElmt, myListener);
di mana elemen DOM myRangeInputElmt
yang Anda inginkan <input type="range">
dan myListener
merupakan fungsi pendengar / penangan yang Anda inginkan dipanggil pada "change"
peristiwa-seperti.
Pendengar Anda mungkin kurang parameter jika diinginkan atau dapat menggunakan event
parameter, yaitu salah satu dari berikut ini akan berfungsi, tergantung pada kebutuhan Anda:
var myListener = function() {...
atau
var myListener = function(evt) {...
(Menghapus pendengar acara dari input
elemen (misalnya menggunakan removeEventListener
) tidak dibahas dalam jawaban ini.)
Deskripsi Demo:
Dalam cuplikan kode di bawah ini, fungsi onRangeChange
menyediakan solusi universal. Sisa kode hanyalah contoh untuk menunjukkan penggunaannya. Setiap variabel yang dimulai dengan my...
tidak relevan dengan solusi universal dan hanya hadir untuk kepentingan demo.
Demo ini menunjukkan rentang / nilai slider serta berapa kali standar "change"
, "input"
dan "onRangeChange"
acara kustom telah dipecat (masing-masing baris A, B dan C). Saat menjalankan cuplikan ini di browser yang berbeda, perhatikan hal berikut saat Anda berinteraksi dengan rentang / slider:
- Di IE11, nilai-nilai dalam baris A dan C keduanya berubah dalam skenario 2 dan 3 di atas sementara baris B tidak pernah berubah.
- Di Chrome dan Safari, nilai dalam baris B dan C keduanya berubah dalam skenario 2 dan 3 sementara baris A hanya berubah untuk skenario 5.
- Di Firefox, nilai dalam baris A hanya berubah untuk skenario 5, perubahan baris B untuk semua lima skenario, dan perubahan baris C hanya untuk skenario 2 dan 3.
- Di semua browser di atas, perubahan pada baris C (solusi yang diusulkan) identik, yaitu hanya untuk skenario 2 dan 3.
Kode Demo:
// 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>
Kredit:
Meskipun implementasinya di sini sebagian besar milik saya, itu terinspirasi oleh jawaban MBourne . Jawaban lain itu menyarankan bahwa peristiwa "input" dan "perubahan" dapat digabungkan dan bahwa kode yang dihasilkan akan berfungsi di browser desktop dan seluler. Namun, kode dalam jawaban itu menghasilkan peristiwa "ekstra" tersembunyi yang dipecat, yang dengan sendirinya bermasalah, dan peristiwa yang dipecat berbeda di antara peramban, masalah selanjutnya. Implementasi saya di sini menyelesaikan masalah tersebut.
Kata kunci:
Jenis slider rentang input JavaScript mengubah input browser kompatibilitas-silang mobile desktop no-jQuery
onchange
tidak menyala. Itu dalam pemecahan masalah yang saya temukan pertanyaan ini.