Несколько месяцев назад я написал статью о MixItUp , популярном плагине jQuery для фильтрации и сортировки. В сегодняшней статье я покажу вам, как создать свой собственный простой фильтруемый компонент с анимацией jQuery и CSS.
Без лишних слов, давайте начнем!
Настройка HTML
В качестве первого шага я покажу вам структуру HTML компонента. Рассмотрим следующую разметку:
<div class="cta filter">
<a class="all active" data-filter="all" href="#" role="button">Show All</a>
<a class="green" data-filter="green" href="#" role="button">Show Green Boxes</a>
<a class="blue" data-filter="blue" href="#" role="button">Show Blue Boxes</a>
<a class="red" data-filter="red" href="#" role="button">Show Red Boxes</a>
</div>
<div class="boxes">
<a class="red" data-category="red" href="#">Box1</a>
<a class="green" data-category="green" href="#">Box2</a>
<a class="blue" data-category="blue" href="#">Box3</a>
<!-- other anchor/boxes here ... -->
</div>
Обратите внимание, что я установил довольно простую разметку. Вот объяснение этого:
- Сначала я определил кнопки фильтра и элементы, которые я хочу фильтровать (мы назовем их целевыми элементами).
- Затем я сгруппировал целевые элементы в три категории (синий, зеленый и красный) и дал им атрибут
data-category
Значение этого атрибута определяет категорию, к которой принадлежит каждый элемент. - Я также назначил атрибут фильтра данных для кнопок фильтра. Значение этого атрибута указывает желаемую категорию фильтра. Например, кнопка с атрибутом / значением
data-filter
data-filter="red"
С другой стороны, кнопка сred
Теперь, когда у вас есть обзор необходимого HTML, мы можем перейти к изучению CSS.
Настройка CSS
Каждый раз, когда категория фильтра активна, соответствующая кнопка фильтра получает data-filter="all"
По умолчанию кнопка с атрибутом active
Вот связанные стили:
data-filter="all"
Кроме того, я собираюсь использовать flexbox для создания макета для целевых элементов.
Смотрите связанные стили ниже:
.filter a {
position: relative;
}
.filter a.active:before {
content: '';
position: absolute;
left: 0;
top: 0;
display: inline-block;
width: 0;
height: 0;
border-style: solid;
border-width: 15px 15px 0 0;
border-color: #333 transparent transparent transparent;
}
Наконец, я определяю две разные CSS-анимации ключевых кадров, которые я буду использовать позже для раскрытия элементов:
.boxes {
display: flex;
flex-wrap: wrap;
}
.boxes a {
width: 23%;
border: 2px solid #333;
margin: 0 1% 20px 1%;
line-height: 60px;
}
Имея разметку и CSS, мы можем начать создавать JavaScript / jQuery.
Настройка jQuery
Посмотрите на код ниже, после чего я объясню, что происходит:
@keyframes zoom-in {
0% {
transform: scale(.1);
}
100% {
transform: none;
}
}
@keyframes rotate-right {
0% {
transform: translate(-100%) rotate(-100deg);
}
100% {
transform: none;
}
}
.is-animated {
animation: .6s zoom-in;
// animation: .6s rotate-right;
}
При каждом нажатии кнопки фильтра происходит следующее:
-
var $filters = $('.filter [data-filter]'),
$boxes = $('.boxes [data-category]');$filters.on('click', function(e) {
e.preventDefault();
var $this = $(this);
$filters.removeClass('active');
$this.addClass('active');var $filterColor = $this.attr('data-filter');
if ($filterColor == 'all') {
$boxes.removeClass('is-animated')
.fadeOut().promise().done(function() {
$boxes.addClass('is-animated').fadeIn();
});
} else {
$boxes.removeClass('is-animated')
.fadeOut().promise().done(function() {
$boxes.filter('[data-category = "' + $filterColor + '"]')
.addClass('is-animated').fadeIn();
});
}
}); - Значение атрибута
active
- Если значение
data-filter
data-filter
Для этого я сначала скрываю их, а затем, когда все элементы становятся скрытыми, показываю их с помощью CSS-анимации сall
rotate-right
- Если значение не
zoom-in
Для этого я сначала скрываю все элементы, а затем, когда все они становятся скрытыми, я показываю только элементы соответствующей категории, используя CSS-анимацию сall
rotate-right
На данный момент важно уточнить одну вещь. Обратите внимание на синтаксис метода zoom-in
Это выглядит следующим образом:
fadeOut()
Вы, вероятно, более знакомы с этим синтаксисом, хотя:
$boxes.fadeOut().promise().done(function() {
// callback's body
});
Эти декларации имеют разные значения:
- В первом случае обратный вызов выполняется только после того, как все целевые элементы становятся скрытыми. Вы можете узнать больше информации об этом подходе, посетив раздел обещания () документации jQuery.
- Во втором случае обратный вызов запускается несколько раз. В частности, он выполняется каждый раз, когда элемент становится скрытым.
Демонстрация ниже использует анимацию $boxes.fadeOut(function() {
// callback's body
});
И эта демонстрация использует анимацию zoom-in
Конечно, вышеупомянутые CSS-анимации не являются обязательными. Если вам не нравятся эти конкретные анимации, не стесняйтесь удалять их и открывать элементы, используя только метод rotate-right
Теперь, когда вы понимаете, как работает компонент, я покажу вам, как создать его другой вариант.
Анимация элементов последовательно
До сих пор вы, возможно, заметили, что все элементы появляются одновременно. Теперь я изменю код, чтобы показать их последовательно:
fadeIn()
Код выше выглядит аналогично предыдущему, но есть несколько отличительных отличий:
- Во-первых, я использую метод each () для перебора целевых элементов. Плюс, когда он зацикливается, я получаю индекс текущего элемента (который начинается с нуля) и умножаю его на число (например, 200). Полученное число передается в качестве аргумента методу
$filters.on('click', function(e) {
Это число указывает количество миллисекунд, которые каждый элемент должен ждать, прежде чем исчезнуть.// same code as above here
if ($filterColor == 'all') {
$boxes.removeClass('is-animated')
.fadeOut().finish().promise().done(function() {
$boxes.each(function(i) {
$(this).addClass('is-animated').delay((i++) * 200).fadeIn();
});
});
} else {
$boxes.removeClass('is-animated')
.fadeOut().finish().promise().done(function() {
$boxes.filter('[data-category = "' + $filterColor + '"]').each(function(i) {
$(this).addClass('is-animated').delay((i++) * 200).fadeIn();
});
});
}
}); - Затем я использую метод finish (), чтобы остановить текущую анимацию для выбранных элементов в определенных случаях. Чтобы понять его использование, вот сценарий: нажмите кнопку фильтра, а затем, прежде чем появятся все элементы, нажмите кнопку еще раз. Вы заметите, что все элементы исчезают. Аналогично, запустите этот тест снова после удаления двух экземпляров этого метода. В таком случае вы увидите, что элементы получают нежелательные эффекты. Иногда правильно вызвать этот метод может быть сложно. Для этого примера мне пришлось немного поэкспериментировать, пока я не нашел, где мне его разместить.
Демонстрация ниже анимирует отфильтрованные элементы последовательно, используя анимацию delay
Демонстрация ниже анимирует отфильтрованные элементы последовательно, используя анимацию zoom-in
Вывод
Этот же компонент может быть построен без jQuery и может иметь лучшую производительность, но возможность использовать rotate-right
fadeIn()
fadeOut()
Дайте мне знать в комментариях, если у вас есть другое решение или способ улучшить код.