我正在寻找一个可行的示例或小提琴,该示例或提琴具有对价格范围以及某些属性(例如“正在销售”)的过滤。基本上,我想将商品过滤到其价格范围,并查看在该价格范围内也在销售的产品。我可以使用价格范围,但是当选中多个复选框时如何实现多个范围。另外,如何实现对销售属性的过滤?
感谢您的帮助。
答案 0 :(得分:1)
HTML的结构和data-*
属性的分配很杂乱。使用大量的div会使代码难以确定目的(如果有)。
对于问题而言,诸如[data-date]
之类的属性不是必需的(在实际代码中也可能不是必需的)。尽管有效,属性[min]
和[max]
在复选框上不是标准的,请使用[data-min]
和[data-max]
并确保在使用带有数字值的任何属性时将其转换为真数字。
在选定的价格范围内,与待售商品和有关的有用性令人怀疑,因为所售商品均在价格范围内。如果分配了.sale
类,则应仅显示销售项目。演示中将对详细信息进行评论。
// Clicking summary calls toggleFilters()
$('summary').on('click', toggleFilters);
/*
Any changes to form.filter calls filterItems()
The second parameter (event.data) indicates what is considered $(this)
*/
$('.filter').on('change', ':checkbox', filterItems);
// If details is closed, the table cells are shown and the .filter is reset
function toggleFilters(e) {
if (!!$(this).parent('details').attr('open')) {
$('tbody td').show();
$('.filter')[0].reset();
}
}
/*
//A Hide all cells in tbody
//B On each checkbox...
if it is checked and has class .priceRange...
...get its [data-min] and [data-max] into an array and add that to the ranges array
//C if it is checked and has class .saleItems sales flag is true
*/
function filterItems(e) {
let ranges = [];
let sales = false;
$('tbody td').hide(); //A
$(':checkbox').each(function() {
if (this.checked) {
if ($(this).is('.priceRange')) { //B
let min = Number($(this).data('min'));
let max = Number($(this).data('max'));
ranges.push([min, max]);
}
if ($(this).is('.saleItems')) { //C
sales = true;
}
}
});
/*
//A On each [data-price] cell...
//B Collect all [data-item] cells into an array
//C Collect all .img cells into an array
//D if [data-price] has .sale class use the [data-sale] value
//E for each sub array in the ranges array...
//F Run between() first param is price, second param is min of sub array third param
is max of sub array
//G if true then show cells [data-price], [data-item], and .img cells associated with
current index of the arrays images and items
//H if sales flag is true and current checkbox is checked and has the .saleItems class...
do the same as line G
*/
$('.products').find('[data-price]').each(function(index) {
const items = $('[data-item]').toArray();
const images = $('.img').toArray();
let price = this.matches('.sale') ?
Number($(this).data('sale')) : Number($(this).data('price'))
for (let range of ranges) {
if (between(price, range[0], range[1])) {
$(this).show();
$(images[index]).show();
$(items[index]).show();
}
}
if (sales && $(this).is('.sale')) {
$(this).show();
$(images[index]).show();
$(items[index]).show();
}
});
}
/*
Utility function that determines if a given number is in a given range
*/
function between(num, min, max) {
return num >= min && num <= max;
}
/*
Utility function that will set the images of .img cells with an array of urls
*/
function setImages(array) {
$('.img').each(function(index) {
$(this).css('background-image', `url(${array[index]})`);
});
}
/* Utility function that sets colspan values according to max number of cells in a row
*/
function tableStructure() {
let cs = [];
$('tr').each(function() {
let size = $(this).children().length;
cs.push(size);
});
let sorted = cs.sort();
$('.cs').attr('colspan', sorted[sorted.length - 1]);
$('tbody').find('tr').last().prev('tr').find('td').css('border-bottom', '0');
}
const images = ['https://www.dhresource.com/webp/m/0x0s/f2-albu-g6-M00-F1-0F-rBVaSFqzohOAJ_2FAAFgtbG9J2U328.jpg/women-new-large-size-casual-tops-loose-ladies.jpg', 'https://www.sherainbow.com/1634-large_default/pogt-casual-long-sleeve-t-shirt-women-loose-fit-wifey-print-slouchy-shirt-top-pink-cb12e6qb3bp.jpg', 'https://sc02.alicdn.com/kf/HTB1ZlLYbHsTMeJjy1zeq6AOCVXar/New-Fashion-Design-Women-plain-black-t.jpg', 'https://aritzia.scene7.com/is/image/Aritzia/large/s19_07_a06_63877_16624_on_a.jpg', 'https://cdn.forcast.com.au/media/catalog/product/cache/image/e9c3970ab036de70892d86c6d221abfe/1/8/18p928blk_18t946sto_frontfull_117_cm_2_7.jpg', 'https://image.skechers.com/img/productimages/xlarge/52675_NVOR.jpg', 'https://static.enko-running-shoes.com/2019/img/v5/chaussure-running-enko.jpg'];
tableStructure();
setImages(images);
.products {
table-layout: fixed;
}
caption,
th {
text-align: left;
font-size: 1.15rem;
}
caption {
font-size: 1.5rem;
font-weight: 700
}
td {
border-bottom: 3px ridge grey;
}
tbody td {
padding-bottom: 5px
}
.dept tr:first-of-type>th::before {
content: attr(data-dept);
font-size: 1.25rem
}
.category th::before {
content: attr(data-cat)
}
.item>td::before {
content: attr(data-item);
font-size: 1.2rem
}
.price>td::before {
content: '$'attr(data-price)
}
.price>td::after {
content: '\a0'
}
.price>td.sale::before {
content: '$'attr(data-price);
text-decoration: line-through red
}
.price>td.sale::after {
content: '$'attr(data-sale);
color: green
}
.img {
background-size: contain;
background-repeat: no-repeat;
background-position: center;
min-width: 100px;
min-height: 100px;
}
label {
display: inline-block;
width: 150px;
margin: 0 5px;
border-bottom: 1px solid black;
}
details {
cursor: pointer
}
tbody tr:last-of-type td {
border-bottom: 0;
}
summary {
font-size: 1.25rem;
border-top: 3px ridge grey
}
<table class="products">
<caption>Shop</caption>
<tbody class='dept'>
<tr>
<th class='cs' data-dept='Apparel'></th>
</tr>
<tr class='category'>
<th class='cs' data-cat='Shirts'></th>
</tr>
<tr class='item'>
<td data-item='item 1'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 2'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 3'></td>
<td class='img' rowspan='2'></td>
</tr>
<tr class='price'>
<td data-price='9.99'><br></td>
<td data-price='23.99'><br></td>
<td class='sale' data-price='32.99' data-sale='17.99'><br></td>
</tr>
<tr class='category'>
<th class='cs' data-cat='Pants'></th>
</tr>
<tr class='item'>
<td data-item='item 4'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 5'></td>
<td class='img' rowspan='2'></td>
</tr>
<tr class='price'>
<td class='sale' data-price='39.99' data-sale='12.99'><br></td>
<td data-price='75.99'><br></td>
</tr>
<tr class='category'>
<th class='cs' data-cat='Shoes'></th>
</tr>
<tr class='item'>
<td data-item='item 6'></td>
<td class='img' rowspan='2'></td>
<td data-item='item 7'></td>
<td class='img' rowspan='2'></td>
</tr>
<tr class='price'>
<td data-price='39.99'><br></td>
<td class='sale' data-price='125.99' data-sale='77.99'><br></td>
</tr>
</tbody>
<tfoot>
<tr>
<td class='cs'>
<form class='filter'>
<details>
<summary>Filters</summary>
<label><input class="priceRange" data-min='0' data-max='9.99' type="checkbox" value='true'>Under $10</label>
<label><input class="priceRange" data-min='10' data-max='19.99' type="checkbox">$10 to $20</label>
<label><input class="priceRange" data-min='20' data-max='29.99' type="checkbox">$20 to $30</label>
<label><input class="priceRange" data-min='30' data-max='39.99' type="checkbox">$30 to $40</label>
<label><input class="priceRange" data-min='40' data-max='999' type="checkbox">Over $40</label>
<label><input class="saleItems" type="checkbox" value='true'>On Sale</label>
</details>
</form>
</td>
</tr>
</tfoot>
</table>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
答案 1 :(得分:0)
我不太确定销售过滤器的预期行为是什么,但这应该使您朝着正确的方向前进: updated plunkr
$('.priceFilter').on('change', (e) => {
var filters = $('.priceRange:checked')
.toArray()
.map(el => ({
min: $(el).attr('min'),
max: $(el).attr('max'),
sale: $(el).attr('data-sale')
}));
if (!filters.length) {
$('.item').show();
} else {
$('.item').hide();
var sale = filters.some(el => el.sale == 'True') ? 'True' : 'False';
filters
.forEach(elm => $('.item')
.filter((i, el) =>
parseFloat($(el).attr('data-price')) >= elm.min &&
parseFloat($(el).attr('data-price')) <= elm.max &&
$(el).attr('data-sale') == sale)
.show());
}
});