我正在练习JS,并且一直在研究过滤机制。
可以在this小提琴中找到该代码。
我偶然发现了以下问题:
当我点击 size 过滤器时, foundSize 类似乎已添加到适当的元素中,无论如何 立即删除。您可以在控制台中观察到这一点。
我的猜测是嵌套循环中有问题,但我不知道这是什么。该问题可以在第132-138行找到,该行发生了添加/删除类。
for (let j = 0; j < filterableSizes.length; j++) {
const singleFilterableSize = filterableSizes[j].dataset.size;
if( activeFilterArray.indexOf(filterableSizes[j].dataset.size) > -1 ) {
filterables[i].classList.add('foundSize');
} else {
filterables[i].classList.remove('foundSize');
}
}
为什么会这样?我该如何解决?
谢谢:)
function createSizeFilters() {
const sizeFilterWrapper = document.querySelector('.size-filter-wrapper');
const sizesFromProducts = Array.from(document.querySelectorAll('.a-product label'));
const sizesNames = sizesFromProducts.map(sizeName => sizeName.textContent);
const uniqSizes = [ ...new Set(sizesNames) ];
const uniqSizesValues = uniqSizes.values();
let cnt1 = 1;
let cnt2 = 1;
for (const value of uniqSizesValues) {
const sizeOption = document.createElement('div');
sizeOption.classList.add('size-option');
sizeOption.setAttribute('data-size', `${value}`);
const sizeOptionLabel = document.createElement('label');
sizeOptionLabel.classList.add('option-label', 'size-label');
sizeOptionLabel.textContent = value;
sizeOptionLabel.setAttribute('for', `size-input-${cnt1++}`);
const sizeInput = document.createElement('input');
sizeInput.classList.add('filter-input', 'size-input');
sizeInput.setAttribute('type', 'checkbox');
sizeInput.setAttribute('id', `size-input-${cnt2++}`);
sizeInput.setAttribute('value', `${value}`);
sizeInput.setAttribute('name', `${value}`);
sizeOption.appendChild(sizeOptionLabel);
sizeOption.appendChild(sizeInput);
sizeFilterWrapper.appendChild(sizeOption);
}
}
function createColorFilters() {
const colorFilterWrapper = document.querySelector('.color-filter-wrapper');
const colorsFromProducts = Array.from(document.querySelectorAll('.a-product'));
const colorsNames = colorsFromProducts.map(colorName => colorName.dataset.color);
const uniqColors = [ ...new Set(colorsNames) ];
const uniqColorsValues = uniqColors.values();
let cnt1 = 1;
let cnt2 = 1;
for (const value of uniqColorsValues) {
const colorOption = document.createElement('div');
colorOption.classList.add('color-option');
colorOption.setAttribute('data-color', `${value}`);
const colorOptionLabel = document.createElement('label');
colorOptionLabel.classList.add('option-label', 'color-label');
colorOptionLabel.textContent = value;
colorOptionLabel.setAttribute('for', `color-input-${cnt1++}`);
const colorInput = document.createElement('input');
colorInput.classList.add('filter-input', 'color-input');
colorInput.setAttribute('type', 'checkbox');
colorInput.setAttribute('id', `color-input-${cnt2++}`);
colorInput.setAttribute('value', `${value}`);
colorInput.setAttribute('name', `${value}`);
colorOption.appendChild(colorOptionLabel);
colorOption.appendChild(colorInput);
colorFilterWrapper.appendChild(colorOption);
}
}
async function filterProducts() {
const filters = document.querySelectorAll('.filter-input');
let activeFilterArray = [];
await getActiveFilters(filters, activeFilterArray);
}
function getActiveFilters(filters, activeFilterArray) {
for (let i = 0; i < filters.length; i++) {
filters[i].addEventListener('change', function() {
const filterTerm = this.value,
filterState = this.checked,
filterParentCat = this.parentNode.parentNode.dataset.filtercategory;
this.classList.toggle('active-filter');
this.previousElementSibling.classList.toggle('bold');
if(filterState == true) {
activeFilterArray.push(filterTerm);
} else {
activeFilterArray.splice( activeFilterArray.indexOf(filterTerm), 1 );
}
filterFilterables(activeFilterArray);
});
}
}
function filterFilterables(activeFilterArray) {
const filterables = document.querySelectorAll('.a-product');
for (let i = 0; i < filterables.length; i++) {
if( (activeFilterArray.length > 0) ) {
// COLORS ~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~
const filterableColor = filterables[i].dataset.color;
if( activeFilterArray.indexOf(filterableColor) > -1 ) {
filterables[i].classList.add('foundColor');
} else {
filterables[i].classList.remove('foundColor');
}
// SIZES ~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~
const filterableSizes = filterables[i].querySelectorAll('.a-swatch');
console.log(filterableSizes);
for (let j = 0; j < filterableSizes.length; j++) {
const singleFilterableSize = filterableSizes[j].dataset.size;
if( activeFilterArray.indexOf(filterableSizes[j].dataset.size) > -1 ) {
filterables[i].classList.add('foundSize');
} else {
filterables[i].classList.remove('foundSize');
}
}
} else {
filterables[i].classList.remove('foundColor');
filterables[i].classList.remove('foundSize');
}
}
}
createSizeFilters();
createColorFilters();
filterProducts();
.filterables, .filters-wrapper { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; }
.a-product { width: 100px; height: 100px; border: 2px solid black; }
<section class="the-collection-products">
<div class="filters-wrapper">
<!-- Size Filters -->
<div>
<span>Size</span>
<div class="filter-wrapper size-filter-wrapper" id="size-filter-wrapper" data-filtercategory="Size Filters"></div>
</div>
<!-- Color Filters -->
<div>
<span>Color</span>
<div class="filter-wrapper color-filter-wrapper" id="color-filter-wrapper" data-filtercategory="Color Filters"></div>
</div>
</div>
<br/> <br/> <br/>
<div class="filterables">
<div class="a-product" data-available="true" data-color="Blue" data-sustainable="yes">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg disabled foundSize" data-size="SM">
<label class="vhf-center z1 disabled" for="product-31021058785368">SM</label>
<input id="product-31021058785368" type="radio" name="SM" data-size="SM">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="M">
<label class="vhf-center z1" for="product-31021058818136">M</label>
<input id="product-31021058818136" type="radio" name="M" data-size="M">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="L">
<label class="vhf-center z1" for="product-31021058850904">L</label>
<input id="product-31021058850904" type="radio" name="L" data-size="L">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="XL">
<label class="vhf-center z1" for="product-31021058883672">XL</label>
<input id="product-31021058883672" type="radio" name="XL" data-size="XL">
</div>
</div>
<div class="a-product" data-available="true" data-color="Red" data-sustainable="">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="M">
<label class="vhf-center z1" for="product-31021096075352">M</label>
<input id="product-31021096075352" type="radio" name="M" data-size="M">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg disabled" data-size="L">
<label class="vhf-center z1 disabled" for="product-31021096108120">L</label>
<input id="product-31021096108120" type="radio" name="L" data-size="L">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="XL">
<label class="vhf-center z1" for="product-31021096140888">XL</label>
<input id="product-31021096140888" type="radio" name="XL" data-size="XL">
</div>
</div>
<div class="a-product" data-available="true" data-color="Green" data-sustainable="">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg foundSize" data-size="SM">
<label class="vhf-center z1" for="product-31021083852888">SM</label>
<input id="product-31021083852888" type="radio" name="SM" data-size="SM">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="M">
<label class="vhf-center z1" for="product-31021083885656">M</label>
<input id="product-31021083885656" type="radio" name="M" data-size="M">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="L">
<label class="vhf-center z1" for="product-31021083918424">L</label>
<input id="product-31021083918424" type="radio" name="L" data-size="L">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="XL">
<label class="vhf-center z1" for="product-31021083951192">XL</label>
<input id="product-31021083951192" type="radio" name="XL" data-size="XL">
</div>
</div>
<div class="a-product" data-available="true" data-color="White" data-sustainable="yes">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="Size Free">
<label class="vhf-center z1" for="product-31257402638424">Size Free</label>
<input id="product-31257402638424" type="radio" name="Size Free" data-size="Size Free">
</div>
</div>
<div class="a-product" data-available="true" data-color="White" data-sustainable="">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="Size Free">
<label class="vhf-center z1" for="product-31257393168472">Size Free</label>
<input id="product-31257393168472" type="radio" name="Size Free" data-size="Size Free">
</div>
</div>
<div class="a-product" data-available="true" data-color="White" data-sustainable="">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="Size Free">
<label class="vhf-center z1" for="product-31257394348120">Size Free</label>
<input id="product-31257394348120" type="radio" name="Size Free" data-size="Size Free">
</div>
</div>
<div class="a-product" data-available="true" data-color="Blue" data-sustainable="">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg foundSize" data-size="SM">
<label class="vhf-center z1" for="product-31024749936728">SM</label>
<input id="product-31024749936728" type="radio" name="SM" data-size="SM">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg disabled" data-size="M">
<label class="vhf-center z1 disabled" for="product-31024749969496">M</label>
<input id="product-31024749969496" type="radio" name="M" data-size="M">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg disabled" data-size="L">
<label class="vhf-center z1 disabled" for="product-31024750002264">L</label>
<input id="product-31024750002264" type="radio" name="L" data-size="L">
</div>
<div class="a-swatch size-swatch relative vhf-center flex-column-lg disabled" data-size="XL">
<label class="vhf-center z1 disabled" for="product-31024750035032">XL</label>
<input id="product-31024750035032" type="radio" name="XL" data-size="XL">
</div>
</div>
<div class="a-product" data-available="true" data-color="Black" data-sustainable="">
<div class="a-swatch size-swatch relative vhf-center flex-column-lg" data-size="Size Free">
<label class="vhf-center z1" for="product-31257301221464">Size Free</label>
<input id="product-31257301221464" type="radio" name="Size Free" data-size="Size Free">
</div>
</div>
</div>
</section>
答案 0 :(得分:1)
为什么会这样
之所以发生这种情况,是因为filterableSizes
循环在找到任何选定的大小时分配了foundSize
,但是您正在循环所有大小,并且对于未选择的每个大小,它都会失败。
换句话说,您选择SM
并期望具有small
属性的每个项目都具有一个foundSize
类,但是代码为每个项目都这样做:
我选择的(sm)过滤器是否匹配拳头尺寸(sm)->是->分配foundSize
我选择的(sm)过滤器是否与第二个尺寸(M)相匹配->否->删除foundSize
我该如何解决?
找到大小后,中断内部循环。
for (let j = 0; j < filterableSizes.length; j++) {
const singleFilterableSize = filterableSizes[j].dataset.size;
if( activeFilterArray.indexOf(filterableSizes[j].dataset.size) > -1 ) {
filterables[i].classList.add('foundSize');
break;
}
filterables[i].classList.remove('foundSize');
}