Кнопка фильтр работает не правильно

Рейтинг: 0Ответов: 1Опубликовано: 28.04.2023

Вот сценарий. Сайт перезагружен, все элементы показаны(не отфильтрованы) нажимаю на кнопку-фильтр например "Машины", видно в devtools что класс добавляется , НО реакции нету, не фильтруются элементы. После ВТОРОГО нажатия, когда класс удаляется, ВОТ тогда отфильтрованные элементы появляются и вот так КНОПКА-ФИЛЬТР фильтрует НАОБОРОТ. Когда класс добавлен>фильтр сбрасывается и показываются все элементы, когда класс удален> отфильтрованные элементы появляются. Помогите пожалуйста и спасибо за понимание введите сюда код

filterSelection("all")
function filterSelection(c) {
  var x, i;
  x = document.getElementsByClassName("filterDiv");
  if (c == "all" || document.getElementsByClassName("active-fltr").length == 0) c = "";
  // Добавить класс "show" (display:block) к отфильтрованным элементам и удалите класс "show" из элементов, которые не выбраны
  for (i = 0; i < x.length; i++) {
    w3RemoveClass(x[i], "show");
    if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
  }
}

// Показать отфильтрованные элементы
function w3AddClass(element, name) {
  var i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    if (arr1.indexOf(arr2[i]) == -1) {
      element.className += " " + arr2[i];
    }
  }
}

// Скрыть элементы, которые не выбраны
function w3RemoveClass(element, name) {
  var i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    while (arr1.indexOf(arr2[i]) > -1) {
      arr1.splice(arr1.indexOf(arr2[i]), 1);
    }
  }
  element.className = arr1.join(" ");
}

// Добавить активный класс к текущей кнопке управления (выделите ее)
var btnContainer = document.getElementById("myBtnContainer");
var btns = btnContainer.getElementsByClassName("btn-fltr");
for (var i = 0; i < btns.length; i++) {
  btns[i].addEventListener("click", function() {
    var current = document.getElementsByClassName("active-fltr");
    if (current.length > 0 && current[0] !== this) {
      current[0].className = current[0].className.replace("active-fltr", "");
    }
    if (this.classList.contains("active-fltr")) {
      this.classList.remove("active-fltr");
    } else {
      this.classList.add("active-fltr");
    }
    
  });
}
.container-fltr{
  overflow: hidden;
  flex-basis: 100%;
  display: flex;
  
}
.filterDiv {
  float: left;
  background-color: #2196F3;
  color: #ffffff;
  width: 100px;
  line-height: 100px;
  text-align: center;
  margin: 2px;
  display: none; /* Скрыто по умолчанию */
  }
  
  /* В класс "show" добавляется к отфильтрованные элементы */
  .show {
  display: block;
  }
  
  /* Стиль кнопок */
  .btn-fltr {
  padding: 12px 16px;
  background-color: #fff;
  cursor: pointer;
  border-radius: 99px;
  border: 2px solid transparent
  }
  
  /* Добавить светло-серый фон на наведении курсора мыши */
  .btn-fltr:hover {

  }
  
  /* Добавить темный фон для активной кнопки */
  .active-fltr {
  background: #FFFFFF;
  box-shadow: 4px 4px 20px rgba(0, 0, 0, 0.1);
  border-radius: 99px;
  box-sizing: border-box !important; 
  border: 2px solid #44AF69;
  }
<div id="myBtnContainer">
                    <button class="btn btn-fltr "> Машины</button>
                    <button class="btn btn-fltr "> Животные</button>
                    <button class="btn btn-fltr "> Фрукты</button>
                    <button class="btn btn-fltr "> Цветы</button>
                  </div>
                  <div class="container-fltr">
                    <div class="filterDiv cars">БМВ</div>
                    <div class="filterDiv colors">Апельсин</div>
                    <div class="filterDiv cars">Вольво</div>
                    <div class="filterDiv colors">Красный</div>
                    <div class="filterDiv cars ">Мустанг</div>
                    <div class="filterDiv colors">Синий</div>
                    <div class="filterDiv animals">Кот</div>
                    <div class="filterDiv animals">Собака</div>
                    <div class="filterDiv fruits">Арбуз</div>
                    <div class="filterDiv fruits ">Киви</div>
                    <div class="filterDiv fruits">Банан</div>
                    <div class="filterDiv fruits">Лимон</div>
                    <div class="filterDiv animals">Корова</div>
                  </div>

Ответы

▲ 1Принят

Проблема заключается в том, что по клику на кнопку идет два действия:

  1. Вызывается функция filterSelection
  2. Вызывается событие 'click' из addEventListener.

Ожидается, что сперва сработает click, в котором установится активный класс для кнопки фильтра, а потом уже по нему отфильтруется.

По факту, все работает наоборот - сперва фильтруем по старому значению, а потом устанавливаем новое.

В качестве решения накидал костыль ввиде добавления в filterFunction setTimeout на 1мс, чтобы изменить порядок вызовов в eventLoop.

filterSelection("all")

function filterSelection(c) {
  console.log('function');
  setTimeout(() => {
    var x, i;
    x = document.getElementsByClassName("filterDiv");
    if (c == "all" || document.getElementsByClassName("active-fltr").length == 0) c = "";
    // Добавить класс "show" (display:block) к отфильтрованным элементам и удалите класс "show" из элементов, которые не выбраны
    for (i = 0; i < x.length; i++) {
      w3RemoveClass(x[i], "show");
      if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
    }
  }, 0)
}

// Показать отфильтрованные элементы
function w3AddClass(element, name) {
  var i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    if (arr1.indexOf(arr2[i]) == -1) {
      element.className += " " + arr2[i];
    }
  }
}

// Скрыть элементы, которые не выбраны
function w3RemoveClass(element, name) {
  var i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    while (arr1.indexOf(arr2[i]) > -1) {
      arr1.splice(arr1.indexOf(arr2[i]), 1);
    }
  }
  element.className = arr1.join(" ");
}

// Добавить активный класс к текущей кнопке управления (выделите ее)
var btnContainer = document.getElementById("myBtnContainer");
var btns = btnContainer.getElementsByClassName("btn-fltr");
for (var i = 0; i < btns.length; i++) {
  btns[i].addEventListener("click", function() {
    console.log('click');
    var current = document.getElementsByClassName("active-fltr");
    if (current.length > 0 && current[0] !== this) {
      current[0].className = current[0].className.replace("active-fltr", "");
    }
    if (this.classList.contains("active-fltr")) {
      this.classList.remove("active-fltr");
    } else {
      this.classList.add("active-fltr");
    }

  });
}
.container-fltr {
  overflow: hidden;
  flex-basis: 100%;
  display: flex;
}

.filterDiv {
  float: left;
  background-color: #2196F3;
  color: #ffffff;
  width: 100px;
  line-height: 100px;
  text-align: center;
  margin: 2px;
  display: none;
  /* Скрыто по умолчанию */
}


/* В класс "show" добавляется к отфильтрованные элементы */

.show {
  display: block;
}


/* Стиль кнопок */

.btn-fltr {
  padding: 12px 16px;
  background-color: #fff;
  cursor: pointer;
  border-radius: 99px;
  border: 2px solid transparent
}


/* Добавить светло-серый фон на наведении курсора мыши */

.btn-fltr:hover {}


/* Добавить темный фон для активной кнопки */

.active-fltr {
  background: #FFFFFF;
  box-shadow: 4px 4px 20px rgba(0, 0, 0, 0.1);
  border-radius: 99px;
  box-sizing: border-box !important;
  border: 2px solid #44AF69;
}
<div id="myBtnContainer">
  <button class="btn btn-fltr "> Машины</button>
  <button class="btn btn-fltr "> Животные</button>
  <button class="btn btn-fltr "> Фрукты</button>
  <button class="btn btn-fltr "> Цветы</button>
</div>
<div class="container-fltr">
  <div class="filterDiv cars ">БМВ</div>
  <div class="filterDiv colors">Апельсин</div>
  <div class="filterDiv cars">Вольво</div>
  <div class="filterDiv colors">Красный</div>
  <div class="filterDiv cars ">Мустанг</div>
  <div class="filterDiv colors">Синий</div>
  <div class="filterDiv animals">Кот</div>
  <div class="filterDiv animals">Собака</div>
  <div class="filterDiv fruits">Арбуз</div>
  <div class="filterDiv fruits ">Киви</div>
  <div class="filterDiv fruits">Банан</div>
  <div class="filterDiv fruits">Лимон</div>
  <div class="filterDiv animals">Корова</div>
</div>

Правильным вариантом будет, в событии addEventListener, после установки активного фильтра вызвать функцию фильтрации. А из html-разметки убрать все вызовы onclick="filterSelection('cars')"