Создание двойного ползунка (double range slider) с помощью NoUiSlider — это отличное решение, когда нужно дать пользователям возможность выбирать диапазон значений, например, для фильтрации цен или других числовых параметров. В этой статье мы рассмотрим, как создать двойной ползунок (или double range slider) с помощью плагина NoUiSlider.

Когда дело касается пользовательского интерфейса, удобство и точность ввода данных становятся важными критериями. Один из самых простых и интуитивно понятных инструментов для этого — ползунок, особенно когда требуется указать не одно, а два значения: минимальное и максимальное. Например, фильтрация товаров по цене на сайте магазина.

В JavaScript существует множество решений для создания ползунков, но одним из наиболее популярных и гибких является библиотека NoUiSlider. Она проста в установке и имеет множество настроек. Сейчас мы покажем, как сделать двойной ползунок и связать его с текстовыми полями для ввода значений.

Установка NoUiSlider

Для начала вам нужно добавить библиотеку в ваш проект. Как и любой современный плагин, NoUiSlider можно подключить через CDN или загрузить локально.

При локальной загрузке нужные нам файлы находятся в папке dist

В нашем примере я уже подключил необходимые стили и скрипты:

<link rel="stylesheet" href="css/nouislider.min.css" />
<script src="js/nouislider.min.js"></script>

Создание структуры HTML

Мы создаем простой макет страницы с двумя текстовыми полями, где пользователь может вводить минимальное и максимальное значения, и сам ползунок, с помощью которого можно эти значения регулировать. Вот как это выглядит:

<div class="container">
  <div class="wrapper">
    <div class="silder">
      <div class="flex flex--column">
        <h1 class="slider__title">Двойной ползунок (плагин NoUiSlider)</h1>
        <p class="slider__subtitle">
          Используйте ползунок или вводите диапазон значений в поле
        </p>
      </div>
      <div class="flex flex--h-center flex--v-center">
        <input type="number" name="min_num" id="min_num" class="slider__field" placeholder="от" />
        <span class="slider__separator">—</span>
        <input type="number" name="max_num" id="max_num" class="slider__field" placeholder="до" />
      </div>
        <div class="slider__self" id="slider"></div>
    </div>
  </div>
</div>

Что здесь происходит?

  • Заголовок и описание: просто добавляем немного контекста для пользователя.
  • Два текстовых поля:  сюда пользователь может ввести минимальное и максимальное значения вручную.
  • Сам ползунок: элемент, который будет визуально отображать диапазон значений и позволять их менять.

Стилизация

Для того чтобы ползунок выглядел красиво, мы добавили немного CSS. В примере выше вы увидите базовые стили для полей ввода, самого ползунка и его маркеров. Мы также задали яркий цвет для выделения выбранного диапазона:

/* Основные стили для фона страницы */
body {
  background-color: #4285f4; /* Синий фон */
}

/* Стили для заголовка ползунка */
.slider__title {
  font-size: 26px; /* Размер текста */
  margin-bottom: 10px; /* Отступ снизу */
  text-align: center; /* Выравнивание текста по центру */
}

/* Стили для подзаголовка */
.slider__subtitle {
  margin-bottom: 30px; /* Отступ снизу */
  text-align: center; /* Выравнивание текста по центру */
}

/* Стили для текстовых полей ввода значений */
.slider__field {
  width: 100px; /* Ширина поля */
  padding: 10px; /* Внутренние отступы */
  border-radius: 5px; /* Скругленные углы */
  background-color: #fff; /* Белый фон */
  border: 1px solid #bbb; /* Серые границы */
  font-size: 20px; /* Размер текста */
  text-align: center; /* Выравнивание текста по центру */
}

/* Изменение стиля поля при фокусе */
.slider__field:focus {
  border: 1px solid #4285f4; /* Синяя граница при фокусе */
}

/* Стили для разделителя между полями */
.slider__separator {
  font-size: 20px; /* Размер текста */
  font-weight: 300; /* Тонкий шрифт */
  line-height: 1; /* Высота строки */
  margin-left: 10px; /* Отступ слева */
  margin-right: 10px; /* Отступ справа */
}

/* Стили для самого ползунка */
.slider__self {
  width: 500px; /* Ширина ползунка */
  cursor: pointer; /* Указатель меняется на руку при наведении */
  height: 7px; /* Высота ползунка */
  border: none; /* Убираем границы */
  background-color: #dedede; /* Серый фон для трека */
  margin-top: 30px; /* Отступ сверху */
}

/* Стили для выделенной части ползунка между значениями */
.slider__self .noUi-connect {
  background-color: rgba(66, 133, 244, 0.5); /* Полупрозрачный синий цвет для соединения */
}

/* Стили для маркеров (ползунков) */
.slider__self .noUi-handle {
  cursor: pointer; /* Указатель меняется на руку при наведении */
  height: 30px; /* Высота маркера */
  width: 30px; /* Ширина маркера */
  top: -12px; /* Смещение сверху для выравнивания */
  right: -9px; /* Смещение справа для точной позиции */
  border-radius: 50%; /* Скругляем маркеры до формы круга */
  border: none; /* Убираем границы */
  box-shadow: none; /* Убираем тени */
  background-color: rgba(66, 133, 244, 1); /* Ярко-синий цвет маркера */
}

/* Убираем дефолтные стили маркеров */
.slider__self .noUi-handle::after {
  display: none; /* Отключаем псевдоэлемент ::after */
}

.slider__self .noUi-handle::before {
  display: none; /* Отключаем псевдоэлемент ::before */
}

/* Основные стили контейнера */
.container {
  width: 100%; /* Ширина 100% от экрана */
  max-width: 1200px; /* Максимальная ширина */
  padding: 0 20px; /* Внутренние отступы по горизонтали */
  height: 100%; /* Высота 100% от родительского контейнера */
  margin: 0 auto; /* Центрируем блок */
  display: flex; /* Используем Flexbox */
  flex-direction: column; /* Выстраиваем элементы по колонке */
  align-items: center; /* Центрируем по горизонтали */
  justify-content: center; /* Центрируем по вертикали */
}

/* Стили обертки контента */
.wrapper {
  background-color: #fff; /* Белый фон */
  padding: 50px; /* Внутренние отступы */
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.06); /* Легкая тень для объема */
  border-radius: 20px; /* Скругленные углы */
}

/* Общие стили для Flexbox */
.flex {
  display: flex; /* Включаем Flexbox */
}

/* Вертикальная ориентация элементов */
.flex--column {
  flex-direction: column; /* Элементы выстраиваются вертикально */
}

/* Горизонтальное центрирование */
.flex--h-center {
  justify-content: center; /* Центрируем элементы по горизонтали */
}

/* Вертикальное центрирование */
.flex--v-center {
  align-items: center; /* Центрируем элементы по вертикали */
}

Логика JavaScript

Теперь приступим к настройке самого ползунка. Мы будем использовать noUiSlider.create(), чтобы задать начальные значения, минимумы и максимумы, а также связывать ползунок с нашими текстовыми полями.

const slider = document.querySelector("#slider");

const formatForSlider = {
  from: function (formattedValue) {
    return Number(formattedValue); // Преобразуем форматированное значение в число
  },
  to: function (numericValue) {
    return Math.round(numericValue); // Округляем число до ближайшего целого
  },
};

noUiSlider.create(slider, {
  start: [200, 800], // Начальные значения ползунка
  connect: true, // Соединяет два значения цветом
  range: {
    min: 0, // Минимальное значение
    max: 1000, // Максимальное значение
  },
  format: formatForSlider, // Форматируем значения при вводе/выводе
});

Разбор кода

  • slider: это элемент, который будет превращен в ползунок.
  • formatForSlider: это объект, который управляет преобразованием значений. Он нужен, чтобы округлять значения, так как плавающие числа могут создавать неудобства пользователям.
  • noUiSlider.create(): создает сам ползунок. Мы указываем стартовые значения [200, 800], задаем минимальный и максимальный диапазон значений от 0 до 1000 и добавляем соединение между двумя значениями ползунка для наглядности.

Связывание с текстовыми полями

Теперь добавим логику, которая будет обновлять значения в текстовых полях при изменении ползунка и наоборот.

const formatValues = [
  document.getElementById("min_num"), // Поле для минимального значения
  document.getElementById("max_num"), // Поле для максимального значения
];

slider.noUiSlider.on("update", function (values, handle) {
  formatValues[handle].value = values[handle]; // Обновляем поля при движении ползунка
});

Что происходит?

  • При изменении положения ползунка событие update срабатывает каждый раз, когда одно из значений меняется.
  • values: массив значений ползунка.
  • handle: индекс ручки (0 — левая, 1 — правая), это помогает определить, какое поле обновить: минимальное или максимальное.