Как запретить повторное выполнение Function, когда конкретный ITEM уже был нажат?
const filter = () => {
const menu = document.querySelector('.portfolio__menu'),
items = menu.querySelectorAll('li'),
wrapper = document.querySelector('.portfolio__blocks'),
markAll = wrapper.querySelectorAll('.all'),
no = document.querySelector('.portfolio-no');
const typeFilter = (markType) => {
let cName = wrapper.getElementsByClassName(markType);
markAll.forEach(mark => {
mark.style.display = 'none';
mark.classList.remove('animated', 'fadeIn');
});
no.style.display = 'none';
no.classList.remove('animated', 'fadeIn');
if (cName.length >= 1) {
[...cName].forEach(mark => {
mark.style.display = 'block';
mark.classList.add('animated', 'fadeIn');
});
} else {
no.style.display = 'block';
no.classList.add('animated', 'fadeIn');
}
};
items.forEach(item => {
item.addEventListener('click', () => {
typeFilter(item.className);
});
});
menu.addEventListener('click', (e) => {
let target = e.target;
if (target && target.tagName == "LI") {
items.forEach(btn => btn.classList.remove('active'));
target.classList.add('active');
}
});
};
filter();
.portfolio__menu {
display: flex;
flex-wrap: wrap;
justify-content: left;
margin-top: 40px;
margin-bottom: 30px;
border-top: 2px solid white;
}
li {
margin-bottom: 20px;
display: inline-block;
font-family: 'Arial', sans-serif;
list-style-type: none;
font-size: 19px;
line-height: 21px;
padding: 15px 20px;
cursor: pointer;
color: #fff;
box-shadow: inset 0 3px 0 0 #F5D6AB;
background-color: rgba(128, 128, 128, 0.4);
transition: all .3s ease-in;
}
li.active,
li:hover {
box-shadow: inset 0 3px 0 0 #C66C49;
background-color: #F5D6AB;
}
.portfolio__blocks {
max-width: 1200px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr;
grid-gap: 10px;
}
.portfolio__block {
width: 1fr;
height: 100px;
background: grey;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 25px;
}
.portfolio-no {
display: none;
}
.animated {
animation-duration: 1s;
animation-fill-mode: both;
}
.fadeIn {
animation-name: fadeIn;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<div class="portfolio__heading">
<ul class="portfolio__menu">
<li class="all active">All</li>
<li class="latest">Latest</li>
<li class="ux-design">UX-Design</li>
<li class="front-end">Front-end</li>
<li class="ui-design">UI-Design</li>
</ul>
</div>
<div class="portfolio__blocks">
<div class="portfolio__block all latest">
1
</div>
<div class="portfolio__block all latest">
2
</div>
<div class="portfolio__block all latest">
3
</div>
<div class="portfolio__block all ux-design">
4
</div>
<div class="portfolio__block all ux-design">
5
</div>
<div class="portfolio__block all ui-design">
6
</div>
<div class="portfolio__block all ui-design">
7
</div>
<div class="portfolio__block all front-end">
8
</div>
<div class="portfolio__block all front-end">
9
</div>
<div class="portfolio__block all front-end">
10
</div>
</div>
<div class="portfolio-no">
<p>I have not done such work yet</p>
</div>
Проблема в том что если ещё раз кликнуть активный пункт меню то появится: I have not done such work yet - сообщение о том, что таких элементов нет. Как это исправить? Должно работать как сейчас, но если нажать активный пункт меню еще раз все должно оставаться, то-есть нажал пункт Latest - подтянулись блоки с классом Latest, Нажал еще раз Latest - блоки остались на прежнем месте. Пробовал через event.stopPropagation() - не помогло(если я все правильно сделал). Всем Спасибо!
Ответы (1 шт):
Если не ошибаюсь, проблема в этой строчке:
typeFilter(item.className);
Когда вы вторично кликаете на пункте меню, в className находится не только название типа вроде latest, но и маркер активности, то есть latest active. Соответственно, let cName = wrapper.getElementsByClassName(markType); ничего не находит, так как у вас нет div-блоков с классом вроде latest active, а есть только latest.
Возможные выходы:
Разделить маркировку активности и тип задания. Например, передавать тип через другой атрибут вроде
data-атрибутов — см. HTMLElement.dataset. Наверное, это сложнее добавить, но так будет логичнее и надёжнее по сравнению с другими способами.Ещё в обработчике щелчка на меню проверять наличие класса
activeв списке классовli, и если он есть, не вызыватьtypeFilter(item.className);. Наверное, самый экономный способ, хоть он и оставит смешение семантики и представления. Можно добавить к предыдущему способу, это решит обе проблемы)Убирать маркировку активности из аргумента, например:
typeFilter(item.className.replace(' active', ''));Это проще добавить, но останется смешение семантики и представления, и это будет больше похоже на костыль, на мой вкус)