Несколько фильтров с использованием onclick JavaScript и HTML - PullRequest
2 голосов
/ 25 марта 2019

Задача

Я пытаюсь создать двойной фильтр, в котором вы можете комбинировать фильтры из нескольких категорий. Например, первая категория фильтров - это годы, а вторая - типы носителей. Я хочу сделать так, чтобы вы могли фильтровать только по годам, типу мультимедиа или по типу медиа по годам (музыка из 1960-х). Кроме того, я пытаюсь держать выбранные фильтры выделенными, чтобы вы могли отслеживать, какие из них активны (я попытался выделить их жирным шрифтом, и это работает для первого набора фильтров, но не для второго. Как решить эта проблема?

Codepen

https://codepen.io/erutuf/pen/ZPwdBq

1010 * Покушение * filterSelection("all") function filterSelection(c) { var x, i; x = document.getElementsByClassName("filterDiv"); if (c == "all") c = ""; 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(" "); } // Add active class to the current button (highlight it) var btnContainer = document.getElementById("myBtnContainer"); var btns = btnContainer.getElementsByClassName("btn"); for (var i = 0; i < btns.length; i++) { btns[i].addEventListener("click", function(){ var current = document.getElementsByClassName("active"); current[0].className = current[0].className.replace(" active", ""); this.className += " active"; }); } .filterDiv { float: left; background-color: white; color: black; width: 37vw; line-height: 100px; text-align: center; margin: 5px; display: none; margin-right: 15px; } .show { display: block; } .container { margin-top: 20px; overflow: hidden; } /* Style the buttons */ .btn { border: none; outline: none; padding: 0; padding-right: 40px; background-color: white; cursor: pointer; font-size: 16px; font-weight: normal; } .btn:hover { } .btn.active { font-weight: bold; } .content{ font-size:16px; line-height:20px; text-align:left; } <div id="myBtnContainer" align="center" style="line-height: 20pt"> <!-- <button class="btn active" onclick="filterSelection('all')"> Show all</button> Show ALL --> <button class="btn active" onclick="filterSelection('ShowAll')">Show all</button> <button class="btn" onclick="filterSelection('1950')">1950</button> <button class="btn" onclick="filterSelection('1960')">1960</button> <button class="btn" onclick="filterSelection('1970')">1970</button> </div> <br> <div id="myBtnContainer" align="center" style="line-height: 20pt"> <!-- <button class="btn active" onclick="filterSelection('all')"> Show all</button> Show ALL --> <button class="btn" onclick="filterSelection('AllMedia')">All Media</button> <button class="btn" onclick="filterSelection('Movies')">Movies</button> <button class="btn" onclick="filterSelection('Music')">Music</button> <button class="btn" onclick="filterSelection('Newspapers')">Newspapers</button> </div> <br><br> <div class="filterDiv AllShapes ShowAll 1950 Newspapers"> <div class="content"> 1950 Newspapers Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </div> </div> <div class="filterDiv AllShapes ShowAll 1960 Music"> <div class="content"> 1960 Music Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </div> </div> <div class="filterDiv AllShapes ShowAll 1960 Newspapers"> <div class="content"> 1960 Newspapers Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </div> </div>

Ответы [ 3 ]

1 голос
/ 25 марта 2019

Самый простой способ - использовать входы <label> и type="radio".
Вы можете стилизовать внутренний элемент <i>, смежный (+) со входом :checked.

Сохраните ссылки фильтра ( реквизиты ) в data-filterable="value1 value2 valueZ" пробел с разделителями.

Хитрость в том, чтобы:

  • on изменить событие, получить проверенные значения входных данных как массив.
  • Скрыть все элементы (добавить класс .is-hidden)
  • возвращает отфильтрованное подмножество элемента в show - в зависимости от того, присутствуют ли все проверенные значения в data-filterable реквизитах (также в виде массива).

Приведенный ниже пример будет работать для любого количества наборов фильтров:

const el_filters = document.querySelectorAll('[name="year"], [name="type"]'),
  el_filterable = document.querySelectorAll('[data-filterable]');

const applyFilter = () => {

  // Filter checked inputs
  const el_checked = [...el_filters].filter(el => el.checked && el.value);
  
  // Collect checked inputs values to array
  const filters = [...el_checked].map(el => el.value);
  
  // Get elements to filter
  const el_filtered = [...el_filterable].filter(el => {
    const props = el.getAttribute('data-filterable').trim().split(/\s+/);
    return filters.every(fi => props.includes(fi))
  });

  // Hide all
  el_filterable.forEach(el => el.classList.add('is-hidden'));

  // Show filtered
  el_filtered.forEach(el => el.classList.remove('is-hidden'));
}

// Assign event listener
el_filters.forEach(el => el.addEventListener('change', applyFilter));
// Init
applyFilter();
/* FILTER INPUTS */

.filterInputs {
  padding-bottom: 5px;
}

.filterInputs input {
  display: none;
}

.filterInputs label {
  display: inline-block;
  position: relative;
  padding: 10px 20px;
  cursor: pointer;
  user-select: none; /* prevent highlight */
}

.filterInputs i {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  box-shadow: inset 0 0 0 2px #0bf;
  z-index: -1;
}

.filterInputs input:checked + i {
  background: #0bf;
}


/* HELPER CLASSES */

.is-hidden {
  display: none;
}
<div class="filterInputs">
  <label><input type="radio" name="year" value="" checked><i></i>All years</label>
  <label><input type="radio" name="year" value="1950"><i></i>1950</label>
  <label><input type="radio" name="year" value="1960"><i></i>1960</label>
  <label><input type="radio" name="year" value="1970"><i></i>1970</label>
</div>

<div class="filterInputs">
  <label><input type="radio" name="type" value=""><i></i>All types</label>
  <label><input type="radio" name="type" value="movies"><i></i>Movies</label>
  <label><input type="radio" name="type" value="music" checked><i></i>Music</label>
  <label><input type="radio" name="type" value="newspapers"><i></i>Newspapers</label>
</div>

<div data-filterable="1950 newspapers">1950 Newspapers</div>
<div data-filterable="1960 music">1960 Music</div>
<div data-filterable="1960 newspapers">1960 Newspapers</div>
1 голос
/ 25 марта 2019

Я использовал селектор атрибута ([filter][group]) для этого сценария,

(function(){
  const selectedFilters = [];

  // [].slice.call => converts HTMLCollection to Array

  const yearFilters = [].slice.call(document.querySelectorAll('[filter][group="year"]'));
  const mediaFilters = [].slice.call(document.querySelectorAll('[filter][group="media"]'));
  const allFilters = yearFilters.concat(mediaFilters);
  
  const filterContents = [].slice.call(document.querySelectorAll('.filterDiv'));

  // add click event to all filters
  allFilters.forEach((filter) => {
    filter.addEventListener('click', filterToggle);
  });
    
  function filterToggle() {
    const filter = this.getAttribute('filter');
    const group = this.getAttribute('group');

    resetMediaFilters();
    
    if(group === 'year') {
      resetYearFilters();
      mediaFilters[0].classList.add('active');
    }    

    this.classList.add('active');
    applyFilter();
  }
  
  function resetYearFilters() {
    yearFilters.forEach(filter => filter.classList.remove('active'));
  }
  
  function resetMediaFilters() {
    mediaFilters.forEach(filter => filter.classList.remove('active'));
  }
  
  function resetFilterContent() {
    filterContents.forEach(content => content.classList.remove('show'));
  }

  function applyFilter() {
    const selectedFilters = [].slice.call(document.querySelectorAll('[filter].active'))
                        .map(filter => filter.getAttribute('filter'));

// class starts with number is a invalid query selector, so using attribute selector for class
    const selector = ["filterDiv"].concat(selectedFilters).map(filter => '[class~="'+ filter +'"]').join('');
    
    resetFilterContent();
    
    document.querySelectorAll(selector).forEach(content => content.classList.add('show'));
  }
  
  // initialize
  applyFilter();
})();
.filterDiv {
  float: left;
  background-color: white;
  color: black;
  width: 37vw;
  line-height: 100px;
  text-align: center;
  margin: 5px;
  display: none;
     margin-right: 15px;
}




.show {
  display: block;
}

.container {
  margin-top: 20px;
  overflow: hidden;
}

/* Style the buttons */
.btn {
  border: none;
  outline: none;
    padding: 0;
    padding-right: 40px;
    background-color: white;
  cursor: pointer;
    font-size: 16px;
 font-weight: normal;
}

.btn:hover {
}

.btn.active {
  font-weight: bold;
}



.content{
  font-size:16px;
  line-height:20px;
  text-align:left;
}
<div id="myBtnContainer" align="center" style="line-height: 20pt">
  <button class="btn active" filter="ShowAll" group="year">Show all</button>
  <button class="btn" filter="1950" group="year">1950</button>
  <button class="btn" filter="1960" group="year">1960</button>
  <button class="btn" filter="1970" group="year">1970</button>
</div>
<br>
<div id="myBtnContainer" align="center" style="line-height: 20pt">
  <button class="btn active" filter="AllMedia" group="media">All Media</button>
  <button class="btn" filter="Movies" group="media">Movies</button>
  <button class="btn" filter="Music" group="media">Music</button>
  <button class="btn" filter="Newspapers" group="media">Newspapers</button>
</div>

<br><br>

 <div class="filterDiv AllMedia ShowAll 1950 Newspapers">
<div class="content">
  1950 Newspapers Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>


 <div class="filterDiv AllMedia ShowAll 1960 Music">
<div class="content">
  1960 Music Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>


 <div class="filterDiv AllMedia ShowAll 1960 Newspapers">
<div class="content">
  1960 Newspapers Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</div>
0 голосов
/ 25 марта 2019

У вас есть функция document.getElementsByClassName () в javascript, которая может вам здесь помочь.DOCS: https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp Вы можете получить массив элементов, которые соответствуют классу, на который вы хотите нацелиться, и затем можете выполнить итерацию по ним, чтобы добавить / удалить скрытое свойство или класс css, который делает их показанными или скрытыми.То же самое можно применить к кнопкам, которые вы хотите сделать более смелыми.

Пример псевдокода:

Click the RED filter
   Iterate over all elements on the page and
      If it has the RED class, make hidden property = false
      Otherwise, make hidden property = true
   Then, iterate over all buttons of type COLOUR
      If it's the RED button, add it the css class for btn_active
      Otherwise, remove the btn_active class

Если кнопка нажата - ВСЕ, логика немного другая, но это просто вопросигры с if-elses.

Помните, что у вас есть методы addClass и removeClass для каждого элемента.Вам не нужно преобразовывать список классов в массив классов и перебирать их.Это намного проще, чем это: https://www.w3schools.com/howto/howto_js_remove_class.asp

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...