От автора: в этой статье мы пошагово разберем, как создать простой jQuery плагин, который будет сортировать элементы по значениям пользовательских data-атрибутов.
Любопытные могут сразу посмотреть конечный результат в CodePen демо:
Замечание: статья предполагает наличие базового понимания flexbox, а также умения разрабатывать плагины на jQuery. Если данные темы вам не знакомы, перейдите по соответствующим ссылкам.
Вопросы доступности
Для создания плагина мы воспользуемся преимуществами flexbox. По умолчанию флекс ячейки выстраиваются в исходном порядке. С помощью свойства order мы можем изменить этот порядок внутри флекс контейнера. Элементы с меньшим значением order появляются раньше. Смотрите пример ниже:
Если у нескольких элементов задано одно значение order, их очередность определяется исходным порядком.
Свойство order позволяет легко сортировать элементы, однако оно несет в себе определенные ограничения по доступности: данное свойство разрывает исходный порядок и визуальный. Чтобы лучше понять суть проблемы, прочтите эту статью (особенно раздел Source Order vs. Visual Order).
Прежде чем перейти к созданию плагина вам важно понять, что он не будет доступным.
Разметка
Для начала пропишите неупорядоченный список из 12 элементов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<ul class="boxes"> <li> <a href="#"> Box1 <div class="details"> <span class="length">13M</span> <span class="price">670€</span> </div> </a> </li> <!-- остальные элементы списка --> </ul> |
Обратите внимание, что в каждом элементе списка есть блок .details, в котором хранится информация о соответствующем элементе списка. Чуть ниже мы также добавим пользовательские HTML атрибуты, в которых будем хранить информацию.
Замечание: элемент .details необязателен. Мы используем его лишь для того, чтобы лучше понять принцип сортировки целевых элементов.
Далее мы задаем атрибуты, по которым будет производиться сортировка. У нас это атрибуты price и length. Мы используем их имена в пользовательских атрибутах (data-price и data-length) элементов списка. Значения этих атрибутов будут совпадать с текстовыми значениями (только цифры) элементов .length и .price, которые расположены в блоке .details.
Например, атрибуты для первого элемента в списке:
1 2 3 4 5 6 7 8 9 |
<li data-length="13" data-price="670"> <a href="#"> Box1 <div class="details"> <span class="length">13M</span> <span class="price">670€</span> </div> </a> </li> |
Теперь необходимо указать элементы, с помощью которых будет производиться сортировка. Для этого мы возьмем тег select:
1 2 3 4 5 6 7 |
<select class="b-select"> <option disabled selected>Sort By</option> <option data-sort="price:asc">Price Ascending</option> <option data-sort="price:desc">Price Descending</option> <option data-sort="length:asc">Length Ascending</option> <option data-sort="length:desc">Length Descending</option> </select> |
Как вы могли заметить, у всех тегов
1 |
<option data-sort="price:asc"> |
У нас есть атрибут со значением, по которому необходимо произвести сортировку. После значения стоит двоеточие, и следует индикатор «asc» или «desc».
Стили CSS
Наша разметка готова, теперь давайте добавим базовые стили на нашу страницу. Нам необходимо превратить неупорядоченный список в флекс контейнер и присвоить элементам списка ширину width: 25%. Соответствующие CSS стили:
1 2 3 4 5 6 7 8 |
.boxes { display: flex; flex-wrap: wrap; } .boxes li { width: 25%; } |
Создание плагина
Назовем наш плагин numericFlexboxSorting. Прежде чем показать процесс создания, давайте начнем с конца и объясним, как инициализировать плагин.
Инициализация плагина
В двух словах, плагин инициализируется следующим образом:
1 |
$("ваш-тег-select").numericFlexboxSorting(); |
В нашем случае так:
1 |
$(".b-select").numericFlexboxSorting(); |
По умолчанию плагин будет сортировать элементы с классом .boxes li. Это можно изменить, переписав значение свойства elToSort.
1 2 3 |
$(".b-select").numericFlexboxSorting({ elToSort: "элементы-для-сортировки" }); |
Пошаговый разбор
А теперь мы можем перейти к описанию процесса разработки!
Во-первых, необходимо расширить прототип объекта jQuery ($.fn), добавив к нему метод numericFlexboxSorting:
1 2 3 4 5 6 7 |
$.fn.numericFlexboxSorting = function() { const $select = this; // код здесь return $select; }; |
Ключевое слово this в этом методе отсылает нас к тегу select. Как только мы создадим плагин, нам нужно будет возвращать этот тег. Если этого не делать, сцепка методов не сработает.
Разберем пример кода:
1 |
$(".b-select").numericFlexboxSorting().css("background", "red"); |
Если мы не вернем целевой элемент, метод css не сделает ровным счетом ничего.
Мы уже говорили, что плагин по умолчанию будет сортировать элементы с классом .boxes li. Нам нужна возможность изменять это поведение, если появится такая необходимость. Для этого мы воспользуемся jQuery методом extend:
1 2 3 4 5 6 7 |
$.fn.numericFlexboxSorting = function(options) { const settings = $.extend({ elToSort: ".boxes li" }, options); // код здесь }; |
Плагин будет сортировать числа по возрастанию и убыванию. Для этого необходимо создать соответствующие переменные, которые будут использоваться потом:
1 2 3 4 5 6 |
$.fn.numericFlexboxSorting = function(options) { const ascOrder = (a, b) => a - b; const descOrder = (a, b) => b - a; // код здесь }; |
Как только пользователь выберет опцию из выпадающего списка (кроме первой), мы должны вытянуть и оценить ее значение. Для этого нам понадобится событие change:
1 2 3 4 5 6 7 8 9 10 |
$.fn.numericFlexboxSorting = function(options) { const $select = this; $select.on("change", () => { const selectedOption = $select.find("option:selected").attr("data-sort"); sortColumns(settings.elToSort, selectedOption); }); // код здесь }; |
Внутри обработчика события мы:
вытягиваем значение атрибута data-sort для выбранной опции (например, price:asc);
вызываем функцию sortColumns.
Функция sortColumns принимает два параметра:
элементы сортировки;
значение атрибута data-sort для выбранной опции.
Сама функция:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function sortColumns(el, opt) { const attr = "data-" + opt.split(":")[0]; const sortMethod = (opt.includes("asc")) ? ascOrder : descOrder; const sign = (opt.includes("asc")) ? "" : "-"; // 1 const sortArray = $(el).map((i, el) => $(el).attr(attr)).sort(sortMethod); // 2 for (let i = 0; i < sortArray.length; i++) { $(el).filter(`[${attr}="${sortArray[i]}"]`).css("order", sign + sortArray[i]); } } |
Разберем код функции:
В зависимости от атрибута сортировки (например, price или length) мы получаем значение соответствующего data-* атрибута для каждого целевого элемента и храним полученные значения в массиве. Кроме того, в зависимости от того, как пользователь хочет сортировать целевые элементы, мы сортируем массив по возрастанию или убыванию.
Проходимся в цикле по массиву, находим соответствующие элементы и присваиваем им свойство order со значением (положительным или отрицательным), которое определяется значением соответствующего data-* attribute. Например, если пользователь выберет price:asc, то элемент с data-price: 315 получит свойство order: 315.
Если же пользователь выберет price:desc, то элемент получит свойство order: -315.
И наконец, чтобы избежать конфликтов с другими библиотеками, использующими переменную $, мы обернем наш код в моментально выполняемую функцию:
1 2 3 4 5 |
(function($) { $.fn.numericFlexboxSorting = function(options) { // код здесь }; })(jQuery); |
Наш плагин готов. Посмотреть его в живую можно в CodePen демо ниже:
Ограничения в плагине
Пора вспомнить, что в нашем плагине есть одно большое ограничение: он не доступен. Чтобы проверить это, выберите опцию из выпадающего списка и нажмите клавишу на клавиатуре (кликните на блок и нажмите клавишу Tab) для перехода между ссылками. Обратите внимание, что элементы получают фокус по DOM порядку, а не CSS.
Также наш плагин обеспечивает лишь базовый функционал, что ограничивает его работу только определенными условиями. Например, строка со значением атрибута должна содержать только числовое значение. Это значение определяет order (ожидает число) для целевых элементов.
В сети полно надежных и мощных библиотек для сортировки и фильтрации элементов: Isotope, MixItUp.
Поддержка в браузерах
В плагине используется flexbox, т.е. его поддержка зависит от поддержки flexbox в браузерах. К счастью, сегодня у flexbox замечательная поддержка.
Данные о поддержке flexbox в основных браузерах можно найти на Can I Use flexbox?
Следующие шаги
Любите сложности и хотите расширить функционал плагина? Тогда вы можете:
добавить поддержку случайной сортировки;
дать пользователю выбор в кнопке сортировки (тег select, несколько кнопок button или элемент другого типа). Для этого вам понадобятся дополнительные настройки:
1 2 3 4 5 6 7 |
$(".b-select").numericFlexboxSorting({ elToSort: "the-elements-you-want-to-sort", controls: { select: true, // запускает событие change button: false // запускает событие click } }); |
Заключение
В этой статье мы прошли через весь процесс создания плагина на jQuery. Плагин использует возможности flexbox для сортировки элементов по значениям их data-атрибутов.
А что вы думаете? Использовали бы вы такое в будущем? Пытались ли вы как-то по-другому совместить JS и flexbox? Пишите в комментариях.
Автор: George Martsoukos
Источник: //www.sitepoint.com/
Редакция: Команда webformyself.