Очень часто на сайтах интернет-магазинов, и не только, можно фильтры со слайдером выбора диапазона значений. В одном из проектов мне тоже понадобилось сделать такой слайдер.
Первое, что приходит в голову — найти уже готовый и вставить себе на сайт. Тут то я и столкнулся с проблемой. Найденный мною плагин JqueryUI.slider отказался работать на некоторых мобильных устройствах. Проблему я выявить не смог (да не особо и хотел ковыряться в чужом коде) и решил сделать свой "велосипед".
"Велосипед" я решил делать на чистом JavaScript, чтобы не связываться с библиотеками. Как говорит один мой знакомый: "чем меньше "левых" подключений, тем стабильней все работает".
Поэтому, первым делом сверстал такой вот простенький макет
<div class="filter"> <div> <span>Фильтр 1</span> <div><number>10</number><number>50</number></div> <div class="slider"> <div class="block-min" onMouseDown="moveRange(this)" onTouchStart="moveRange(this)"></div> <div class="color-range"></div> <div class="block-max" onMouseDown="moveRange(this)" onTouchStart="moveRange(this)"></div> </div> </div> <div> <span>Фильтр 2</span> <div><number>0</number><number>5</number></div> <div class="slider"> <div class="block-min" onMouseDown="moveRange(this)" onTouchStart="moveRange(this)"></div> <div class="color-range"></div> <div class="block-max" onMouseDown="moveRange(this)" onTouchStart="moveRange(this)"></div> </div> </div> </div>
На экране он выглядит так

Сам слайдер с ползунками находится в блоке с классом "slider" в котором есть еще 2 блока: ползунок минимального значения и ползунок максимального значения диапазона.
В них описаны два события:
- onMouseDown — срабатывает, когда мы захватываем мышью ползунок;
- onTouchStart — срабатывает на мобильных устройствах, при касании пальца к нашему ползунку.
Над slider-ом размещается блок с двумя числами — это и есть наши максимальное и минимальное значения.
<div><number>0</number><number>5</number></div>
Теперь перейдем к самой функции, которая вызывается при клике.
function moveRange (elem) { //Определяем размеры и координаты нашего ползунка var coords = getCoords(elem); /*Определяем зону окрашивания*/ var colorRange = elem.parentElement.children[1]; var f;//устанавливаем флаг для определения мин или макс элемента var value; //значение фильтра /*Определяем второй ползунок и родителя*/ var parent = {} parent.element = elem.parentElement; parent.coords = getCoords(parent.element); var block2 = {} if (elem.classList.contains('block-min')) { block2.element = elem.parentElement.children[2]; block2.coords = getCoords(block2.element); f=0; } else { block2.element = elem.parentElement.children[0]; block2.coords = getCoords(block2.element); f=1; } /*Делаем индикатор вывода значений над ползунком*/ var indicator = document.createElement('div'); if (elem.children.length){ elem.innerHTML = '';//обнуляем предыдущее значение } elem.append(indicator); document.addEventListener('mousemove', onMouseMove);//определяем функцию-обработчик на событие движения мышью document.addEventListener('mouseup', onMouseUp);//определяем функцию-обработчик на событие отпускания кнопки мыши document.addEventListener('touchmove', onMouseMove);//здесь все тоже самое, только на касание пальцем document.addEventListener('touchend', onMouseUp); /*выключаем браузерное событие DaD*/ elem.ondragstart = function(){ return false; }
Функция getCoords позволяет нам получить координаты и размеры наших элементов.
Выглядит она следующим образом.
function getCoords(elem) { /*Получаем координаты относительно окна браузера*/ let coords = elem.getBoundingClientRect(); /*Высчитываем значения координат относительно документа, вычисляя прокрутку документа*/ return {//возвращает объект, который содержит: top : coords.top + window.pageYOffset, //верхнюю координату элемента относительно страницы left : coords.left + window.pageXOffset, //крайнюю левую координату элемента относительно страницы leftX: coords.left, //левую координату относительно страницы rigth : coords.left + window.pageXOffset + coords.width, //крайнюю правую координату bottom : coords.top + window.pageYOffset + coords.height, //нижнюю координату width : coords.width //ширину элемента } }
Теперь опишем функции-обработчики.
Первая функция — onMouseMove, которая вызывается при движении мышью. Она будет отрабатывать только при горизонтальном движении.
function onMouseMove(e) { /*Определяем смещение влево*/ e.preventDefault();//предотвратить запуск выделения элементов /*Определяем положение мыши в зависимости от устройства*/ /*На мобильных устройствах может фиксироваться несколько точек касания, поэтому используется массив targetTouches*/ /*Мы будем брать только первое зафиксированое касание по экрану targetTouches[0]*/ if (e.touches === undefined) { var pos = e.clientX; } else { var pos = e.targetTouches[0].clientX; } /*Устанавливаем границы движения ползунка*/ let newLeft = pos - parent.coords.leftX; let rigthEdge = parent.coords.width - (coords.width+1); if (newLeft<0) { newLeft = 0; } else if (newLeft > rigthEdge) { newLeft = rigthEdge; } if (f == 0 && pos > block2.coords.left-block2.coords.width) { newLeft = block2.coords.left - block2.coords.width - 5 - parent.coords.leftX; }else if (f == 1 && pos < block2.coords.rigth + 5) { newLeft = block2.coords.rigth + 5 - parent.coords.leftX; } /*устанавливаем отступ нашему элементу*/ elem.style.left = newLeft + 'px'; // Определяем значение фильтра let rangeMin = +document.querySelector('.filter number:first-child').innerHTML; let rangeMax = +document.querySelector('.filter number:last-child').innerHTML; if(f==0){ value = (newLeft / (parent.coords.width / (rangeMax - rangeMin)) + rangeMin).toFixed(1); } else { value = (newLeft / (parent.coords.width / (rangeMax - rangeMin))+ 0.3 + rangeMin).toFixed(1); } /*Выводим значение над ползунком*/ indicator.style.position = 'absolute'; indicator.style.fontSize = "14px"; indicator.style.left = - coords.width/2 + "px"; indicator.style.top = parseFloat(window.getComputedStyle(elem).getPropertyValue('top')) - 10 +"px"; /*Для красоты слайдера уберем вывод значений в начальной и конечной точках*/ if (newLeft <= 0){ indicator.innerHTML= ""; } else if (newLeft >= rigthEdge) { indicator.innerHTML= ""; } else { indicator.innerHTML = value; } /*Делаем цветную плашечку диапазона выбора*/ if (f == 0) { colorRange.style.left = newLeft + coords.width + "px"; colorRange.style.width = block2.coords.left - getCoords(elem).left - coords.width + "px"; } else { colorRange.style.left = block2.coords.left - parent.coords.leftX + "px"; colorRange.style.width = getCoords(elem).left - block2.coords.left + "px"; } }
И, наконец, функция-обработчик события "отпускания кнопки" или потери точки касания на мобильных устройствах. Она удаляет все добавленные ранее события и оставляет ползунок на установленном значении.
function onMouseUp() { document.removeEventListener('mouseup', onMouseUp); document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('touchend', onMouseUp); document.removeEventListener('touchmove', onMouseMove); }
И, конечно же, CSS-стили для нашего слайдера
.filter { padding: 30px; width: 500px; } .filter>div { padding-top: 20px; display: -webkit-flex; display: -moz-flex; display: -ms-flex; display: -o-flex; display: flex; -webkit-flex-direction: column; -moz-flex-direction: column; -ms-flex-direction: column; -o-flex-direction: column; flex-direction: column; } .filter>div>div { display: -webkit-flex; display: -moz-flex; display: -ms-flex; display: -o-flex; display: flex; justify-content: space-between; } .filter .slider { margin-top: 10px; position: relative; height: 6px; background: #fff; border: 1px solid #000; } .filter .color-range { position: absolute; background: #a4a4a4; width: 97%; border: none; height: 6px; left: 15px; } .filter .block-min, .block-max { width: 15px; height: 25px; position: absolute; left: 0; top: -11.5px; background: #fff; border: 1px solid #000; border-radius: 4px; z-index: 1; } .filter .block-max{ left: 97%; }
Посмотреть рабочую версию данного слайдера можно здесь.
Все файлы можно скачать с GitHub.
Приятного пользования и легкой работы!
ссылка на оригинал статьи https://habr.com/ru/post/466623/
Добавить комментарий