Очень часто на сайтах интернет-магазинов, и не только, можно фильтры со слайдером выбора диапазона значений. В одном из проектов мне тоже понадобилось сделать такой слайдер.
Первое, что приходит в голову — найти уже готовый и вставить себе на сайт. Тут то я и столкнулся с проблемой. Найденный мною плагин 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.
Приятного пользования и легкой работы!
Автор: zhenya-2304