РЕЗЮМЕ:
Я надаю тут можливість безперешкодного перехресного перегляду веб-браузера без jQuery послідовно реагувати на взаємодію діапазону / слайдера, що неможливо в сучасних браузерах. По суті, всі браузери змушують наслідувати IE11 on("change"...
події для їх on("change"...
або on("input"...
подій. Нова функція ...
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);});
}
... де r
ваш елемент введення діапазону і f
ваш слухач. Слухач буде викликаний після будь-якої взаємодії, яка змінює значення діапазону / повзунка, але не після взаємодій, які не змінюють цього значення, включаючи початкові взаємодії миші або сенсорного керування у поточному положенні слайдера або після переміщення з будь-якого кінця повзунка.
Проблема:
На початок червня 2016 року різні веб-переглядачі відрізняються за рівнем реагування на використання діапазону / слайдера. П'ять сценаріїв актуальні:
- початкове натискання миші (або сенсорний старт) у поточному положенні слайдера
- початкове натискання миші (або сенсорний старт) у новому положенні слайдера
- будь-який наступний рух миші (або дотик) після 1 або 2 по повзунку
- будь-який наступний (миттєвий) рух миші після 1 або 2 повз будь-якого кінця повзунка
- остаточне миші (або сенсорне)
Наступна таблиця показує, як принаймні три різні браузери настільних комп'ютерів відрізняються своєю поведінкою щодо того, на який із вищезазначених сценаріїв вони відповідають:
Рішення:
Ця onRangeChange
функція забезпечує послідовну та передбачувану відповідь між браузером на взаємодію дальності / слайдера. Це змушує всіх браузерів вести себе відповідно до наступної таблиці:
В IE11 код по суті дозволяє всім діяти відповідно до статусу кво, тобто він дозволяє "change"
події функціонувати в стандартному режимі, і "input"
подія не має значення, оскільки вона ніколи не запускається. В інших веб-переглядачах "change"
подія ефективно приглушується (щоб запобігти появі додаткових, а іноді і не очевидних подій). Крім того, "input"
подія запускає свого слухача лише тоді, коли змінюється значення діапазону / слайдера. Для деяких браузерів (наприклад, Firefox) це відбувається тому, що слухач ефективно замовчується в сценаріях 1, 4 та 5 із наведеного вище списку.
(Якщо вам справді потрібна активація слухача в будь-якому сценарії 1, 4 та / або 5, ви можете спробувати включити "mousedown"
/ "touchstart"
, "mousemove"
/ "touchmove"
та / або "mouseup"
/ "touchend"
події. Таке рішення виходить за межі цієї відповіді.)
Функціональність у мобільних браузерах:
Я перевірив цей код у настільних браузерах, але не в будь-яких мобільних браузерах. Однак в іншій відповіді на цій сторінці MBourne показав, що моє рішення тут "..., здається, працює у кожному браузері, який я міг знайти (Win desktop: IE, Chrome, Opera, FF; Android Chrome, Opera і FF, iOS Safari) " . (Спасибі М.Бурне.)
Використання:
Щоб скористатися цим рішенням, включіть onRangeChange
функцію з наведеного вище резюме (спрощений / мінімізований) або фрагмент демо-коду нижче (функціонально ідентичний, але більш зрозумілий) у своєму власному коді. Викликайте це так:
onRangeChange(myRangeInputElmt, myListener);
де myRangeInputElmt
є бажаний <input type="range">
елемент DOM і myListener
є функцією слухача / обробника, на яку потрібно викликати "change"
подібні події.
Ваш слухач може мати параметр за бажанням або може використовувати event
параметр, тобто будь-яке з наступних може працювати, залежно від ваших потреб:
var myListener = function() {...
або
var myListener = function(evt) {...
(Видалення слухача події з input
елемента (наприклад, використання removeEventListener
) у цій відповіді не розглядається.)
Опис демонстрації:
У фрагменті коду нижче функція onRangeChange
забезпечує універсальне рішення. Решта коду - просто приклад для демонстрації його використання. Будь-яка змінна, яка починається з my...
, не має значення для універсального рішення і присутня лише заради демонстрації.
Демонстраційні показує значення діапазону / слайдер, а також кількість разів стандартних "change"
, "input"
і призначені для користувача "onRangeChange"
події обстріляли (рядки A, B і C відповідно). Під час запуску цього фрагмента в різних браузерах зауважте, що ви взаємодієте з діапазоном / повзунком:
- У IE11 значення в рядках A і C змінюються в сценаріях 2 і 3 вище, тоді як рядок B ніколи не змінюється.
- У Chrome та Safari значення у рядках B і C змінюються у сценаріях 2 та 3, тоді як рядок A змінюється лише для сценарію 5.
- У Firefox значення рядка A змінюється лише для сценарію 5, рядок B змінюється для всіх п'яти сценаріїв, а рядок C змінюється лише для 2 та 3 сценаріїв.
- У всіх перерахованих вище браузерах зміни в рядку C (пропоноване рішення) є однаковими, тобто лише для сценаріїв 2 і 3.
Демо-код:
// 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>
Кредит:
Хоча реалізація тут значною мірою власна, вона надихнула відповідь М.Бурна . Ця інша відповідь передбачає, що події "введення" та "зміни" можна об'єднати і що отриманий код буде працювати як у настільних, так і в мобільних браузерах. Однак код у цій відповіді призводить до вилучення прихованих "зайвих" подій, що саме по собі є проблематичним, а випущені події відрізняються між браузерами, подальша проблема. Моя реалізація тут вирішує ці проблеми.
Ключові слова:
Події повзунка діапазону вводу JavaScript змінюють порівнянність вхідного браузера крос-браузерний настільний мобільний no-jQuery
onchange
не стріляє. Саме у вирішенні цієї проблеми я знайшов це питання.