Создание слайдера диапазона значений для фильтра без использования Jquery

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Очень часто на сайтах интернет-магазинов, и не только, можно фильтры со слайдером выбора диапазона значений. В одном из проектов мне тоже понадобилось сделать такой слайдер.


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


  1. onMouseDown — срабатывает, когда мы захватываем мышью ползунок;
  2. 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/


Интересные статьи

Интересные статьи

Привет, Хабр! Сегодня мы начинаем публикацию серии практических материалов для продакт-менеджеров, основателей стартапов и всех остальных, кто хочет приобрести навыки менеджера по раз...
Нам интересно лучше узнать наших слушателей: кто вы и что думаете о подкасте — что нравится, что бесит, что можно улучшить. Пройдите, пожалуйста, опрос. Ваши ответы помогут сделать подкаст лучш...
REST Assured — DSL для тестирования REST-сервисов, который встраивается в тесты на Java. Это решение появилось более девяти лет назад и стало популярным из-за своей простоты и удобного функционал...
Amazon не всегда была королём онлайн-шопинга. Осенью 2004-го компания Джеффа Безоса всё ещё в основном продавала книги и DVD. Её со многих сторон осаждали более успешные конкуренты. Крупные т...
В Челябинске проходят митапы системных администраторов Sysadminka, и на последнем из них я делал доклад о нашем решении для работы приложений на 1С-Битрикс в Kubernetes. Битрикс, Kubernetes, Сep...