Фильтрация DOM элементов на JS
Не смог найти ответа в предыдущем вопросе, поэтому перезадаю*
Дамы и господа, прошу совета. В пример кода выложил фильтр, где есть два споллера, которые должны фильтровать коллекцию li.
Если нажать на первый и выбрать класс, то он отфильтрует, когда нажмёшь на пункт второго споллера - всё сработает, как и должно.
Но если мы выберем ещё раз пункт из второго споллера, то список полностью обнулится, так как выборка делается из существующего списка. Если я сделаю, чтобы он обновлял список, как в первом споллере, то он перестанет фильтровать на основе первого и будет выдавать всегда только список всех предметов не учитывая класс. Как можно пофиксить этот момент? Буду крайне признателен за подсказку.
function openCloseFilter() {
if (document.querySelectorAll(".filter-spoller") !== null) {
document.querySelectorAll(".filter-spoller").forEach((e) => {
e.addEventListener("click", (eve) => {
if (
!eve.currentTarget.children[1].classList.contains(
"filter-spoller-active"
)
) {
const filterBtns = document.querySelectorAll(".filter-spoller");
for (let i = 0; i < filterBtns.length; i++) {
const element = filterBtns[i];
if (element !== undefined) {
element.classList.remove("filter-spoller-btn-active");
// element.children[1].classList.remove("filter-spoller-active");
for (let i = 0; i < element.children.length; i++) {
const asd = element.children[i];
asd.classList.remove("filter-spoller-active");
}
}
}
eve.currentTarget.children[1].classList.add("filter-spoller-active");
eve.currentTarget.classList.add("filter-spoller-btn-active");
} else {
eve.currentTarget.children[1].classList.remove(
"filter-spoller-active"
);
eve.currentTarget.classList.remove("filter-spoller-btn-active");
}
});
});
// console.log(filterSpollers);
}
}
// eve.currentTarget.children[1].classList.remove("filter-spoller-active");
// eve.currentTarget.classList.remove("filter-spoller-btn-active");
openCloseFilter();
const filterLiCollection = document.querySelectorAll(".exTasksLi");
document.querySelectorAll(".filter-spoller-classes").forEach((e) => {
e.addEventListener("click", (eve) => {
let classItem = e.classList[0].split("-")[3];
sortLis(classItem);
}),
false;
});
function sortLis(item) {
filterLiCollection.forEach((e) =>
e.getAttribute("data-class")
? (e.style.display = "block")
: console.log("q")
);
let result = [...filterLiCollection].filter(
(e) => e.getAttribute("data-class") !== item && e.style.display == "block"
);
result.forEach((e) => (e.style.display = "none"));
}
document.querySelectorAll(".filter-spoller-a-subject").forEach((e) =>
e.addEventListener("click", (eve) => {
let subjectItem = e.classList[0].split("-")[3];
sortSubjects(subjectItem);
})
);
function sortSubjects(subjectItem) {
filterLiCollection.forEach((e) => {
let result = [...filterLiCollection].filter(
(e) => e.getAttribute("data-subject") !== subjectItem
);
result.forEach((e) => (e.style.display = "none"));
});
}
.ex-tasks {
@include adaptiveValue('padding-bottom', 104, 64)
}
.ex-tasks__rows {
h1 {
@include adaptiveValue('font-size', 40, 26);
@include adaptiveValue('margin-top', 104, 64);
@include adaptiveValue('margin-bottom', 40, 24);
font-weight: 700;
line-height: 120%;
}
h3 {
@include adaptiveValue('font-size', 18, 14);
margin-bottom: rem(24);
line-height: 140%;
}
h2 {
@include adaptiveValue('font-size', 18, 14);
margin-bottom: rem(24);
line-height: 140%;
transition: transform .3s ease-in-out;
&:hover {
transform: translateX(5px);
}
a {
transition: transform .3s ease-in-out;
}
&:hover {
a {
color: $mainTif;
}
}
}
}
.download-file {}
.download-link-keeper-ex-tasks {
margin-left: 32px;
// position: relative;
}
.documents-list {
li {
h2 {
// margin-left: 12px;
}
position: relative;
}
}
#doc {
position: absolute;
top: -3px;
left: 0;
}
.doc-color-brown {
path {
stroke: transparent;
fill: #A9E44D;
}
}
.doc-color-vanilla {
path {
stroke: transparent;
fill: #4D4B43;
}
}
.doc-color-blue {
path {
stroke: transparent;
fill: #25282B;
}
}
.doc-color-white {
path {
stroke: transparent;
fill: #000;
}
}
.doc-color-black {
path {
stroke: transparent;
fill: #fff;
}
}
@media (orientation: landscape) and (max-height: 500px) {
.documents__rows {
h2 {
margin-bottom: 150px;
}
}
}
.filter-spollers-keeper {
margin-bottom: rem(32);
}
#arrow-filter-spoller {
transition: transform .3s ease-in-out;
position: absolute;
right: 32px;
top: 40%;
path {
stroke: $mainTif;
}
path{
stroke: $pointText;
}
}
.filter-spoller {
position: relative;
background-color: #fff;
color: $mainText;
border: 1px solid $pointText;
border-radius: 10px;
transition: border-radius .3s ease;
line-height: 140%;
padding-top: 8px;
padding-bottom: 8px;
padding-left: 18px;
margin-bottom: rem(8);
margin-right: rem(8);
font-weight: 700;
text-align: left;
@include adaptiveValue("width", 220, 220);
height: 40px;
&__title {
position: absolute;
left: 20px;
top: 7px;
width: 100%;
}
}
.filter-spoller__box {
overflow: hidden;
transition-duration: .5s;
z-index: 20;
position: absolute;
top: 38px;
right: -1px;
left: -1px;
color: $mainText;
@include adaptiveValue("font-size", 16, 14);
font-weight: 400;
background-color: #fff;
border-radius: 10px;
border: 1px solid $pointText;
max-height: 0;
opacity: 0;
transition: max-height .3s ease-in-out, opacity .2s ease, transform .3s ease;
li {
&:hover {
font-weight: 700;
background-color: $bgTif;
color: $mainTif;
}
}
}
.filter-spoller-btn-active {
background-color: #fff;
color: $mainText;
border-radius: 10px 10px 0 0 ;
border-bottom: 0px solid #000;
}
.filter-spoller {
&__content {
border-top: 1px solid #d9d9d9;
}
&__list {
}
}
.filter-spoller-li {
padding-left: rem(20);
&:not(:last-child) {
border-bottom: 1px solid #D9D9D9;
}
padding-top: rem(8);
padding-bottom: rem(8);
}
.filter-spoller-active {
transition: max-height .7s ease-in-out, opacity .01s ease, transform .3s ease;
max-height: 700px;
opacity: 1;
border-radius: 0 0 10px 10px;
border-top: 0px solid #fff;
}
#arrow-infra-leap {
// z-index: 50;
transition: transform .3s ease-in-out;
position: absolute;
// @include adaptiveValue("right", -160, -16);
right: 32px;
top: 40%;
path {
stroke: $mainTif;
}
}
.filter-spoller-opacity {
transition: transform .3s ease, opacity .3s ease;
transform: translateY(-50px);
opacity: 0;
}
.filter-spoller-a {
width: 100%;
height: 100%;
}
<main class="ex-tasks">
<div class="ex-tasks__container">
<section class="ex-tasks__rows">
<h1></h1>
<h3></h3>
<button class="filter-spoller">
<h4 class="filter-spoller__title">Выберите класс </h4>
<div class="filter-spoller__box ">
<div class="filter-spoller__content">
<ul class="filter-spoller__list">
<li class="filter-spoller-li"><a class="filter-spoller-a-7-class filter-spoller-classes" href="#">7 класс</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-8-class filter-spoller-classes" href="#">8 класс</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-9-class filter-spoller-classes" href="#">9 класс</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-10-class filter-spoller-classes" href="#">10 класс</a></li>
</ul>
</div>
</div>
</button>
<button class="filter-spoller">
<h4 class="filter-spoller__title">Выберите предмет </h4>
<div class="filter-spoller__box ">
<div class="filter-spoller__content">
<ul class="filter-spoller__list">
<li class="filter-spoller-li"><a class="filter-spoller-a-math-subject filter-spoller-a-subject" href="#">Математика</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-ruLang-subject filter-spoller-a-subject" href="#">Русский язык</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-physics-subject filter-spoller-a-subject" href="#">Физика</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-chemistry-subject filter-spoller-a-subject" href="#">Химия</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-biology-subject filter-spoller-a-subject" href="#">Биология</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-informatics-subject filter-spoller-a-subject" href="#">Информатика</a></li>
</ul>
</div>
</div>
</button>
<ul class="documents-list document-list-ex-tasks">
<li class="exTasksLi" data-stage="1" data-class="7" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="#" class="download-file" download="">I этап / 7 класс / Математика / 2023</a>
</h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Математика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="ruLang" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Русский язык / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="physics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Физика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="chemistry" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Химия / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="biology" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Биология / 2023</a>
</h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Математика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="ruLang" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Русский язык / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="physics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Физика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="chemistry" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Химия / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="biology" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Биология / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="informatics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Информатика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Математика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="ruLang" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Русский язык / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="physics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Физика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="chemistry" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Химия / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="biology" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Биология / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="informatics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Информатика / 2023</a></h2>
</li>
</ul>
</section>
</div>
</main>
Ответы (2 шт):
Вообщем, сделал через классы. Так проще котнролировать ситуацию.
// Получаем все 18 строчек li. Преобразовываем NodeList в массив, чтобы работали функции высшего порядка (filter, forEach, Map, Reduce)
let filterLiCollection = [...document.querySelectorAll(".exTasksLi")];
// Здесь мы получаем 10 кнопок, пробегаемся через forEach и ставим слушатель на click.
//Чтобы знать, как поступать с той или иной кнопкой, идентифицировать её, мы получаем класс, который на каждой кнопке свой, он выглядит так (filter-spoller-a-9-class) на кнопках с классами, и так (filter-spoller-a-math-subject) на кнопках с предметами. С помощью split делим строку по дефисам и берём из массива слово/цифру, в зависимости от кнопки.
//С помощью тернарного оператора проверяем этот символ и вызываем функцию, аргументов передавая это значение
document.querySelectorAll(".filter-spoller-a-all").forEach((e) => {
e.addEventListener("click", (eve) => {
let partClass = e.classList[0].split("-")[3];
partClass == "7" ? filterThis("7") : false;
partClass == "8" ? filterThis("8") : false;
partClass == "9" ? filterThis("9") : false;
partClass == "10" ? filterThis("10") : false;
partClass == "math" ? filterThis("math") : false;
partClass == "chemistry" ? filterThis("chemistry") : false;
partClass == "biology" ? filterThis("biology") : false;
partClass == "informatics" ? filterThis("informatics") : false;
partClass == "physics" ? filterThis("physics") : false;
partClass == "ruLang" ? filterThis("ruLang") : false;
}),
false;
});
// Это функция, которая принимает число или слова, в зависимости от нажатой кнопки.
const filterThis = (num) => {
//пробегаемся по всему массиву с li элементами
filterLiCollection.forEach((e) => {
//Делаем проверку, чтобы ниженаписанная логика относилась только к своим элементам (без этой проверки не робит)
if (
num == "math" ||
num == "chemistry" ||
num == "biology" ||
num == "informatics" ||
num == "physics" ||
num == "ruLang"
) {
//здесь фильтрация, которая отбирает те элементы, которые не являются нашей целью. Отбираются, чтобы их скрыть
let ewq = filterLiCollection.filter(
(filter) => filter.dataset.subject !== num
);
// Здесь удаляются display-none ТОЛЬКО с тех элементов, которые относятся непосредственно к выбору предмета. Это позволит нам выбрать класс, который сузит поиск до 5 элементов, потом выбрать предмет и перевыбирать его. Он будет перезаписываться. Без этого, уже после двух кликов по фильтрам лист окажется пустым.
filterLiCollection.forEach((el) => el.classList.remove("subject-none"));
//Здесь мы получаем текст в споллере, чтобы менять его на текущий предмет
let subjTitle = document.querySelector(".title-subject");
num == "math" ? (subjTitle.innerHTML = `Математика`) : console.log("");
num == "chemistry" ? (subjTitle.innerHTML = `Химия`) : console.log("");
num == "biology" ? (subjTitle.innerHTML = `Биология`) : console.log("");
num == "informatics"
? (subjTitle.innerHTML = `Информатика`)
: console.log("");
num == "physics" ? (subjTitle.innerHTML = `Физика`) : console.log("");
num == "ruLang"
? (subjTitle.innerHTML = `Русский язык`)
: console.log("");
//Здесь мы добавляем класс, который будет скрывать те элементы, которые мы не выбирали.
ewq.forEach((el) => el.classList.add("subject-none"));
console.log(ewq);
}
});
//Тут всё то же самое, что и в коде выше.
if (num == "7" || num == "8" || num == "9" || num == "10") {
filterLiCollection.forEach((el) => el.classList.remove("class-none"));
let ewq = filterLiCollection.filter(
(filter) => filter.dataset.class !== num
);
document.querySelector(".title-class").innerHTML = `${num} класс`;
ewq.forEach((el) => el.classList.add("class-none"));
console.log(ewq);
}
};
Друзья, если будут вопросы - пишите в комментариях, если будет необходимо - могу добавить html и тд, чтобы было нагляднее, но это - по запросу.
Проблема в неверном порядке применении фильтра.
Для решения достаточно вынести фильтрацию по всем критериям в одно место. При клике на фильтр просто заполнять нужный критерий и выполнять общую функцию.
В этом случае обработчик клика может выглядеть так:
const filters = {}; // критерии фильтрации - ключ: имя фильтра, значение: проверяемое значение
document.querySelectorAll(".filter-spoller-a").forEach((e) => {
e.addEventListener("click", (eve) => {
let [, , , value, criteria] = e.classList[0].split("-"); // получаем из класса фильтр и проверяемое значение
filters[criteria] = value; // сохраняем в объект
applyFilter(filters); // фильтруем список
});
});
Сама фильтрация происходит в applyFilter, где за один проход просто выставляется display:
function applyFilter(filters) {
filterLiCollection.forEach((e) => { // бежим по элементам списка
e.style.display = Object.entries(filters).reduce((acc, [criteria, value]) => acc && (!value || e.dataset[criteria] == value), true) // если элемент соответствует критериям
? '' // сбрасываем `display`
: 'none'; // иначе - скрываем
});
}
Пример:
function openCloseFilter() {
if (document.querySelectorAll(".filter-spoller") !== null) {
document.querySelectorAll(".filter-spoller").forEach((e) => {
e.addEventListener("click", (eve) => {
if (!eve.currentTarget.children[1].classList.contains(
"filter-spoller-active"
)) {
const filterBtns = document.querySelectorAll(".filter-spoller");
for (let i = 0; i < filterBtns.length; i++) {
const element = filterBtns[i];
if (element !== undefined) {
element.classList.remove("filter-spoller-btn-active");
// element.children[1].classList.remove("filter-spoller-active");
for (let i = 0; i < element.children.length; i++) {
const asd = element.children[i];
asd.classList.remove("filter-spoller-active");
}
}
}
eve.currentTarget.children[1].classList.add("filter-spoller-active");
eve.currentTarget.classList.add("filter-spoller-btn-active");
} else {
eve.currentTarget.children[1].classList.remove(
"filter-spoller-active"
);
eve.currentTarget.classList.remove("filter-spoller-btn-active");
}
});
});
}
}
openCloseFilter();
const filterLiCollection = document.querySelectorAll(".exTasksLi");
const filters = {};
document.querySelectorAll(".filter-spoller-a").forEach((e) => {
e.addEventListener("click", (eve) => {
let [, , , value, criteria] = e.classList[0].split("-");
filters[criteria] = value;
applyFilter(filters);
});
});
function applyFilter(filters) {
filterLiCollection.forEach((e) => {
e.style.display = Object.entries(filters).reduce((acc, [criteria, value]) => acc && (!value || e.dataset[criteria] == value), true) ? '' : 'none';
});
}
.ex-tasks {
@include adaptiveValue('padding-bottom', 104, 64)
}
.ex-tasks__rows {
h1 {
@include adaptiveValue('font-size', 40, 26);
@include adaptiveValue('margin-top', 104, 64);
@include adaptiveValue('margin-bottom', 40, 24);
font-weight: 700;
line-height: 120%;
}
h3 {
@include adaptiveValue('font-size', 18, 14);
margin-bottom: rem(24);
line-height: 140%;
}
h2 {
@include adaptiveValue('font-size', 18, 14);
margin-bottom: rem(24);
line-height: 140%;
transition: transform .3s ease-in-out;
&:hover {
transform: translateX(5px);
}
a {
transition: transform .3s ease-in-out;
}
&:hover {
a {
color: $mainTif;
}
}
}
}
.download-file {}
.download-link-keeper-ex-tasks {
margin-left: 32px;
// position: relative;
}
.documents-list {
li {
h2 {
// margin-left: 12px;
}
position: relative;
}
}
#doc {
position: absolute;
top: -3px;
left: 0;
}
.doc-color-brown {
path {
stroke: transparent;
fill: #A9E44D;
}
}
.doc-color-vanilla {
path {
stroke: transparent;
fill: #4D4B43;
}
}
.doc-color-blue {
path {
stroke: transparent;
fill: #25282B;
}
}
.doc-color-white {
path {
stroke: transparent;
fill: #000;
}
}
.doc-color-black {
path {
stroke: transparent;
fill: #fff;
}
}
@media (orientation: landscape) and (max-height: 500px) {
.documents__rows {
h2 {
margin-bottom: 150px;
}
}
}
.filter-spollers-keeper {
margin-bottom: rem(32);
}
#arrow-filter-spoller {
transition: transform .3s ease-in-out;
position: absolute;
right: 32px;
top: 40%;
path {
stroke: $mainTif;
}
path {
stroke: $pointText;
}
}
.filter-spoller {
position: relative;
background-color: #fff;
color: $mainText;
border: 1px solid $pointText;
border-radius: 10px;
transition: border-radius .3s ease;
line-height: 140%;
padding-top: 8px;
padding-bottom: 8px;
padding-left: 18px;
margin-bottom: rem(8);
margin-right: rem(8);
font-weight: 700;
text-align: left;
@include adaptiveValue("width", 220, 220);
height: 40px;
&__title {
position: absolute;
left: 20px;
top: 7px;
width: 100%;
}
}
.filter-spoller__box {
overflow: hidden;
transition-duration: .5s;
z-index: 20;
position: absolute;
top: 38px;
right: -1px;
left: -1px;
color: $mainText;
@include adaptiveValue("font-size", 16, 14);
font-weight: 400;
background-color: #fff;
border-radius: 10px;
border: 1px solid $pointText;
max-height: 0;
opacity: 0;
transition: max-height .3s ease-in-out, opacity .2s ease, transform .3s ease;
li {
&:hover {
font-weight: 700;
background-color: $bgTif;
color: $mainTif;
}
}
}
.filter-spoller-btn-active {
background-color: #fff;
color: $mainText;
border-radius: 10px 10px 0 0;
border-bottom: 0px solid #000;
}
.filter-spoller {
&__content {
border-top: 1px solid #d9d9d9;
}
&__list {}
}
.filter-spoller-li {
padding-left: rem(20);
&:not(:last-child) {
border-bottom: 1px solid #D9D9D9;
}
padding-top: rem(8);
padding-bottom: rem(8);
}
.filter-spoller-active {
transition: max-height .7s ease-in-out, opacity .01s ease, transform .3s ease;
max-height: 700px;
opacity: 1;
border-radius: 0 0 10px 10px;
border-top: 0px solid #fff;
}
#arrow-infra-leap {
// z-index: 50;
transition: transform .3s ease-in-out;
position: absolute;
// @include adaptiveValue("right", -160, -16);
right: 32px;
top: 40%;
path {
stroke: $mainTif;
}
}
.filter-spoller-opacity {
transition: transform .3s ease, opacity .3s ease;
transform: translateY(-50px);
opacity: 0;
}
.filter-spoller-a {
width: 100%;
height: 100%;
}
<main class="ex-tasks">
<div class="ex-tasks__container">
<section class="ex-tasks__rows">
<h1></h1>
<h3></h3>
<button class="filter-spoller">
<h4 class="filter-spoller__title">Выберите класс </h4>
<div class="filter-spoller__box ">
<div class="filter-spoller__content">
<ul class="filter-spoller__list">
<li class="filter-spoller-li"><a class="filter-spoller-a--class filter-spoller-a" href="#">сбросить</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-7-class filter-spoller-a" href="#">7 класс</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-8-class filter-spoller-a" href="#">8 класс</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-9-class filter-spoller-a" href="#">9 класс</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-10-class filter-spoller-a" href="#">10 класс</a></li>
</ul>
</div>
</div>
</button>
<button class="filter-spoller">
<h4 class="filter-spoller__title">Выберите предмет </h4>
<div class="filter-spoller__box ">
<div class="filter-spoller__content">
<ul class="filter-spoller__list">
<li class="filter-spoller-li"><a class="filter-spoller-a--subject filter-spoller-a" href="#">сбросить</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-math-subject filter-spoller-a" href="#">Математика</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-ruLang-subject filter-spoller-a" href="#">Русский язык</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-physics-subject filter-spoller-a" href="#">Физика</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-chemistry-subject filter-spoller-a" href="#">Химия</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-biology-subject filter-spoller-a" href="#">Биология</a></li>
<li class="filter-spoller-li"><a class="filter-spoller-a-informatics-subject filter-spoller-a" href="#">Информатика</a></li>
</ul>
</div>
</div>
</button>
<ul class="documents-list document-list-ex-tasks">
<li class="exTasksLi" data-stage="1" data-class="7" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="#" class="download-file" download="">I этап / 7 класс / Математика / 2023</a>
</h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Математика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="ruLang" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Русский язык / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="physics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Физика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="chemistry" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Химия / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="8" data-subject="biology" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Биология / 2023</a>
</h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Математика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="ruLang" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Русский язык / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="physics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Физика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="chemistry" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Химия / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="biology" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Биология / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="9" data-subject="informatics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Информатика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="math" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Математика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="ruLang" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Русский язык / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="physics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Физика / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="chemistry" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Химия / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="biology" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Биология / 2023</a></h2>
</li>
<li class="exTasksLi" data-stage="1" data-class="10" data-subject="informatics" data-year="2023">
<h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Информатика / 2023</a></h2>
</li>
</ul>
</section>
</div>
</main>