使用不同的价格范围和一个属性进行过滤

时间:2019-07-16 16:02:33

标签: javascript jquery

我正在寻找一个可行的示例或小提琴,该示例或提琴具有对价格范围以及某些属性(例如“正在销售”)的过滤。基本上,我想将商品过滤到其价格范围,并查看在该价格范围内也在销售的产品。我可以使用价格范围,但是当选中多个复选框时如何实现多个范围。另外,如何实现对销售属性的过滤?

感谢您的帮助。

2 个答案:

答案 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());
  }
});