Статьи

Совет: сортируемые пользователем списки с Flexbox и jQuery

Спутник с гигантским магнитом, используемый для сортировки астероидов

В этой статье мы шаг за шагом узнаем, как создать простой плагин jQuery, который сортирует элементы на основе значений их пользовательских атрибутов данных.

Если вас интересует конечный результат, посмотрите соответствующую демонстрацию CodePen:

Примечание. В этой статье предполагается, что у вас есть базовые знания о flexbox , а также о том, как разрабатывать плагины jQuery . Если вы не знакомы с этими темами, не забудьте проверить ссылки.

Проблемы доступности

Чтобы создать наш плагин, мы воспользуемся мощью flexbox.

По умолчанию гибкие элементы располагаются в соответствии с их исходным порядком. Но, используя свойство order , мы можем изменить их порядок внутри родительского flex-контейнера. Элементы с более низкими значениями появляются первыми. Смотрите пример ниже:

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

Хотя свойство order позволяет нам легко переупорядочивать элементы, оно имеет ограничение доступности: оно создает разрыв между исходным порядком и визуальным порядком. Чтобы лучше понять проблему, ознакомьтесь с этой статьей (особенно в разделе «Порядок исходного кода и визуальный порядок»).

Поэтому, прежде чем перейти к рассмотрению того, как создать наш плагин, обратите внимание, что он не будет доступен.

Разметка

Для начала определим неупорядоченный список с двенадцатью элементами списка:

 <ul class="boxes"> <li> <a href="#"> Box1 <div class="details"> <span class="length">13M</span> <span class="price">670€</span> </div> </a> </li> <!-- more list items here --> </ul> 

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

Примечание. Элемент .details самом деле не нужен. Мы используем его только для лучшего понимания того, как сортируются целевые элементы.

Далее мы идентифицируем атрибуты, по которым мы хотим отсортировать. В нашем проекте это атрибуты price и length . Имея это в виду, мы используем их имена для применения пользовательских атрибутов ( data-price и data-length ) к элементам нашего списка. Значения этих атрибутов соответствуют текстовым значениям (только числам) элементов .length и .price которые являются частью элемента .details .

Например, вот атрибуты для первого элемента списка:

 <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> :

 <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> 

Как видите, все элементы <option> (кроме первого) содержат атрибут data-sort . Значение этого атрибута использует следующее соглашение:

 <option data-sort="price:asc"> 

Итак, в качестве значения у нас есть атрибут, по которому мы хотим отсортировать, за которым следует двоеточие вместе с индикатором «asc» или «desc».

Стили CSS

Когда разметка готова, давайте добавим несколько основных стилей на нашу страницу. В частности, мы определяем неупорядоченный список как гибкий контейнер и задаем width: 25% элементов списка width: 25% . Вот соответствующие правила CSS:

 .boxes { display: flex; flex-wrap: wrap; } .boxes li { width: 25%; } 

Сборка плагина

Мы назовем наш плагин numericFlexboxSorting . Прежде чем показывать процесс, которому мы будем следовать при его создании, давайте начнем с конца и объясним, как мы можем его инициализировать.

Инициализация плагина

В общем случае плагин должен быть инициализирован следующим образом:

 $("your-select-tag").numericFlexboxSorting(); 

Например, в нашем случае:

 $(".b-select").numericFlexboxSorting(); 

По умолчанию плагин будет сортировать элементы по классу .boxes li . Мы можем переопределить это поведение, изменив значение elToSort конфигурации elToSort :

 $(".b-select").numericFlexboxSorting({ elToSort: "the-elements-you-want-to-sort" }); 

Шаги Разбивка

Теперь мы готовы описать процесс разработки!

В качестве первого шага мы расширяем объект-прототип jQuery ( $.fn ), добавляя к numericFlexboxSorting метод numericFlexboxSorting :

 $.fn.numericFlexboxSorting = function() { const $select = this; // do stuff here return $select; }; 

В этом методе ключевое слово this ссылается на наш элемент <select> . Как только мы создадим плагин, мы должны вернуть этот элемент. Если мы этого не сделаем, цепочка методов не будет работать.

Рассмотрим этот код, например:

 $(".b-select").numericFlexboxSorting().css("background", "red"); 

Здесь, если мы не вернем целевой элемент, метод css ничего не сделает.

Как мы уже упоминали, плагин будет сортировать элементы по классу .boxes li по умолчанию. Однако мы должны иметь возможность переопределить это поведение, если захотим. Для этого мы используем метод расширения jQuery:

 $.fn.numericFlexboxSorting = function(options) { const settings = $.extend({ elToSort: ".boxes li" }, options); // do stuff here }; 

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

 $.fn.numericFlexboxSorting = function(options) { const ascOrder = (a, b) => a - b; const descOrder = (a, b) => b - a; // do stuff here }; 

Как только пользователь выбирает параметр (кроме первого) из раскрывающегося списка, мы должны извлечь и оценить его значение. Для этого мы используем событие change :

 $.fn.numericFlexboxSorting = function(options) { const $select = this; $select.on("change", () => { const selectedOption = $select.find("option:selected").attr("data-sort"); sortColumns(settings.elToSort, selectedOption); }); // do stuff here }; 

Внутри обработчика событий мы делаем две вещи:

  1. Получить значение атрибута data-sort для выбранного параметра (например, price:asc ).
  2. Вызовите функцию sortColumns .

Функция sortColumns принимает два параметра:

  1. Элементы, которые мы хотим отсортировать.
  2. Значение атрибута data-sort для выбранной опции.

Вот тело этой функции:

 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]); } } 

Давайте объясним, что происходит внутри:

  1. В зависимости от атрибута, который пользователь хочет отсортировать (например, price или length ), мы получаем значение соответствующего data-* attribute для каждого целевого элемента и сохраняем его в массиве. Кроме того, в зависимости от того, как пользователь хочет отсортировать целевые элементы, мы сортируем массив в порядке возрастания или убывания.

  2. Мы перебираем массив, находим связанные элементы и присваиваем им значение свойства order (положительное или отрицательное), которое определяется значением их соответствующего data-* attribute .
    Так, например, если пользователь выбирает опцию price:asc , элемент с data-price: 315 получает order: 315 .

    Как работает плагин, когда мы сортируем в порядке возрастания

    С другой стороны, если пользователь выбирает опцию price:desc , он получает order: -315 .

    Как работает плагин, когда мы сортируем в порядке убывания

Наконец, чтобы предотвратить возможные конфликты с другими библиотеками, которые используют переменную $ , мы заключаем наш код в немедленно вызванное выражение функции, например:

 (function($) { $.fn.numericFlexboxSorting = function(options) { // do stuff here }; })(jQuery); 

Наш плагин готов. Вы можете увидеть его вживую в следующей демонстрации Codepen:

Ограничения плагинов

На данный момент, мы должны напомнить, что наш плагин имеет одно большое ограничение: он недоступен. Чтобы доказать это, выберите вариант в раскрывающемся списке, а затем используйте клавиатуру ( нажмите перо и нажмите клавишу «Tab» ) для навигации по ссылкам. Обратите внимание, что элементы фокусируются в соответствии с их порядком DOM, а не их порядком CSS.

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

Следует также отметить, что плагин предоставляет только базовую функциональность, и поэтому он будет работать только при определенных условиях. Например, строка значения атрибута должна содержать только числовые значения. Помните, что это значение указывает order (ожидает число) для целевых элементов.

Очевидно, что для сортировки и фильтрации элементов существуют более надежные и мощные библиотеки, подобные приведенным ниже:

Специально для MixItUp, есть статья SitePoint, которая охватывает его основы.

Поддержка браузера

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

Могу ли я использовать flexbox? Данные о поддержке функции flexbox в основных браузерах можно найти на сайте caniuse.com.

Следующие шаги

Если вам нравится вызов и вы хотите обогатить функциональность этого плагина, вот несколько вещей, которые вы можете сделать:

  • Добавить поддержку для случайной сортировки.

  • Дайте пользователям возможность выбрать, будет ли элемент управления сортировкой элементом <select> , количеством элементов <button> или даже другим типом элемента управления. Для этого сценария вы можете указать дополнительные параметры, например:

     $(".b-select").numericFlexboxSorting({ elToSort: "the-elements-you-want-to-sort", controls: { select: true, // fires change event button: false // fires click event } }); 

Вывод

В этой статье мы рассмотрели процесс создания плагина jQuery. Этот плагин использует возможности flexbox для сортировки элементов на основе значений их пользовательских атрибутов данных.

Что вы думаете: это то, что вы могли бы использовать в будущем? Задумывались ли вы о других способах объединения JavaScript и flexbox? Дай мне знать в комментариях.