对于使用数据属性进行过滤,在 JS 中如何匹配具有相同单词但顺序不同的 2 个数组?

For filtering using data-attributes, In JS how do I match 2 arrays that have the same words but in a different order?

我正在尝试创建一个使用数据属性的过滤系统,如果选择的项目与元素数据属性的顺序相匹配,我可以让它工作,例如:选择的项目{fun, easy, cheap} 和元素属性的顺序相同,但如果我单击 {easy, cheap, fun},则不会返回任何结果。 任何解决此问题的帮助将不胜感激。

var filterBtns = document.querySelectorAll('.request-btn'),
  slider = document.querySelector('.slider'),
  cardContainers = $('.cards-container'),
  selectedFilters = [];

filterBtns.forEach(function(el) {
  el.addEventListener('click', function() {
    this.classList.toggle('clicked');
    if (this.classList.contains('clicked')) {
      selectedFilters.push(this.dataset.filter);
    } else {
      selectedFilters.splice(selectedFilters.indexOf(this.dataset.filter), 1);
    }
    updateCards();
  });
});

slider.addEventListener('change', function() {
  if (this.value === '0') {
    selectedFilters.push('easy');
  } else if (this.value === '1') {
    selectedFilters.splice(selectedFilters.indexOf('easy', 'diy'), 1);
  } else {
    selectedFilters.push('diy');
  }

  updateCards();
});

var updateCards = function() {
  cardContainers.removeClass('show').filter(function() {
    var data = this.dataset;
    var selectedFiltersValues = selectedFilters.join(' ');
    return selectedFilters.length ? data.filter.includes(selectedFiltersValues) : true;
  }).addClass('show');
}
.card {
  width: 200px;
  border: 1px solid coral;
  margin: 15px;
  padding: 15px;
  float: left;
}

.cards-container {
  display: none;
}

.show {
  display: block;
}

.request-btn.clicked {
  background-color: coral;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div class="filter-container">
  <div class="left-filter">
    <p>EASY<input type="range" class="slider provider-complexity" min="0" max="2" value="1" step="1">DIY</p>
  </div>
  <div class="right-filter">
    <button class="request-btn" data-filter="cheap">Cheap</button>
    <button class="request-btn" data-filter="fun">fun</button>
    <button class="request-btn" data-filter="green">green</button>
    <button class="request-btn" data-filter="big">big</button>
  </div>

</div>
<div class="cards-container show" data-filter="green">
  <div class="card">1 the tag is - green</div>
</div>
<div class="cards-container show" data-filter="fun">
  <div class="card">2 the tag is - fun</div>
</div>
<div class="cards-container show" data-filter="cheap">
  <div class="card">3 the tag is - cheap</div>
</div>
<div class="cards-container show" data-filter="big">
  <div class="card">4 the tag is - big</div>
</div>
<div class="cards-container show" data-filter="cheap big">
  <div class="card">5 the tags are - cheap big</div>
</div>
<div class="cards-container show" data-filter="fun easy cheap">
  <div class="card">6 the tags are - fun easy cheap</div>
</div>
<div class="cards-container show" data-filter="diy">
  <div class="card">7 the tag is - diy</div>
</div>
<div class="cards-container show" data-filter="easy">
  <div class="card">8 hthe tag is - easy</div>
</div>
<div class="cards-container show" data-filter="easy green">
  <div class="card">9 the tags are - easy green</div>
</div>

根据评论更新

根据评论,要求是每个项目都必须包含所有过滤器。如果选择了“便宜”和“大”,则只能返回“便宜”“大”的商品。

变化:

    // Get the individual item filters as an array
    var itemData = data.filter.split(' ')
    return selectedFilters.length
    // match on every
    ? selectedFilters.every(function (val) {
        return itemData.indexOf(val) > -1;
      })
    : true;

var filterBtns = document.querySelectorAll('.request-btn'),
  slider = document.querySelector('.slider'),
  cardContainers = $('.cards-container'),
  selectedFilters = [];

filterBtns.forEach(function(el) {
  el.addEventListener('click', function() {
    this.classList.toggle('clicked');
    if (this.classList.contains('clicked')) {
      selectedFilters.push(this.dataset.filter);
    } else {
      selectedFilters.splice(selectedFilters.indexOf(this.dataset.filter), 1);
    }
    updateCards();
  });
});

slider.addEventListener('change', function() {
  if (this.value === '0') {
    selectedFilters.push('easy');
  } else if (this.value === '1') {
    selectedFilters.splice(selectedFilters.indexOf('easy', 'diy'), 1);
  } else {
    selectedFilters.push('diy');
  }

  updateCards();
});

var updateCards = function() {
  cardContainers.removeClass('show').filter(function() {
    var itemData = data.filter.split(' ')
    return selectedFilters.length
      ? selectedFilters.every(function (val) {
          return itemData.indexOf(val) > -1;
        })
      : true;
  }).addClass('show');
}
.card {
  width: 200px;
  border: 1px solid coral;
  margin: 15px;
  padding: 15px;
  float: left;
}

.cards-container {
  display: none;
}

.show {
  display: block;
}

.request-btn.clicked {
  background-color: coral;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div class="filter-container">
  <div class="left-filter">
    <p>EASY<input type="range" class="slider provider-complexity" min="0" max="2" value="1" step="1">DIY</p>
  </div>
  <div class="right-filter">
    <button class="request-btn" data-filter="cheap">Cheap</button>
    <button class="request-btn" data-filter="fun">fun</button>
    <button class="request-btn" data-filter="green">green</button>
    <button class="request-btn" data-filter="big">big</button>
  </div>

</div>
<div class="cards-container show" data-filter="green">
  <div class="card">1 the tag is - green</div>
</div>
<div class="cards-container show" data-filter="fun">
  <div class="card">2 the tag is - fun</div>
</div>
<div class="cards-container show" data-filter="cheap">
  <div class="card">3 the tag is - cheap</div>
</div>
<div class="cards-container show" data-filter="big">
  <div class="card">4 the tag is - big</div>
</div>
<div class="cards-container show" data-filter="cheap big">
  <div class="card">5 the tags are - cheap big</div>
</div>
<div class="cards-container show" data-filter="fun easy cheap">
  <div class="card">6 the tags are - fun easy cheap</div>
</div>
<div class="cards-container show" data-filter="diy">
  <div class="card">7 the tag is - diy</div>
</div>
<div class="cards-container show" data-filter="easy">
  <div class="card">8 hthe tag is - easy</div>
</div>
<div class="cards-container show" data-filter="easy green">
  <div class="card">9 the tags are - easy green</div>
</div>

原创

你的问题是你加入了你选择的过滤器,然后在你的 updateCards 函数中你正在检查项目 data-filter 是否包括 cheap fun green.

解决方案是检查 selectedFilters 的数组是否包含元素属性。

变化

  const itemData = data.filter.split(' ')
    return selectedFilters.length
    ? selectedFilters.every(function (val) {
        return itemData.indexOf(val) > -1;
      })
    : true;

我已经在下面更新了您的示例。 关于 .some 用法的说明它适用于所有主流浏览器,如果出于某些糟糕的原因需要支持 6-8,则需要一个 polyfill。 CanIUse

var filterBtns = document.querySelectorAll('.request-btn'),
  slider = document.querySelector('.slider'),
  cardContainers = $('.cards-container'),
  selectedFilters = [];

filterBtns.forEach(function(el) {
  el.addEventListener('click', function() {
    this.classList.toggle('clicked');
    if (this.classList.contains('clicked')) {
      selectedFilters.push(this.dataset.filter);
    } else {
      selectedFilters.splice(selectedFilters.indexOf(this.dataset.filter), 1);
    }
    updateCards();
  });
});

slider.addEventListener('change', function() {
  if (this.value === '0') {
    selectedFilters.push('easy');
  } else if (this.value === '1') {
    selectedFilters.splice(selectedFilters.indexOf('easy', 'diy'), 1);
  } else {
    selectedFilters.push('diy');
  }

  updateCards();
});

var updateCards = function() {
  cardContainers.removeClass('show').filter(function() {
    var data = this.dataset;
    return selectedFilters.length
    ? selectedFilters.some(function (val) {
        return data.filter.includes(val);
      })
    : true;
  }).addClass('show');
}
.card {
  width: 200px;
  border: 1px solid coral;
  margin: 15px;
  padding: 15px;
  float: left;
}

.cards-container {
  display: none;
}

.show {
  display: block;
}

.request-btn.clicked {
  background-color: coral;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div class="filter-container">
  <div class="left-filter">
    <p>EASY<input type="range" class="slider provider-complexity" min="0" max="2" value="1" step="1">DIY</p>
  </div>
  <div class="right-filter">
    <button class="request-btn" data-filter="cheap">Cheap</button>
    <button class="request-btn" data-filter="fun">fun</button>
    <button class="request-btn" data-filter="green">green</button>
    <button class="request-btn" data-filter="big">big</button>
  </div>

</div>
<div class="cards-container show" data-filter="green">
  <div class="card">1 the tag is - green</div>
</div>
<div class="cards-container show" data-filter="fun">
  <div class="card">2 the tag is - fun</div>
</div>
<div class="cards-container show" data-filter="cheap">
  <div class="card">3 the tag is - cheap</div>
</div>
<div class="cards-container show" data-filter="big">
  <div class="card">4 the tag is - big</div>
</div>
<div class="cards-container show" data-filter="cheap big">
  <div class="card">5 the tags are - cheap big</div>
</div>
<div class="cards-container show" data-filter="fun easy cheap">
  <div class="card">6 the tags are - fun easy cheap</div>
</div>
<div class="cards-container show" data-filter="diy">
  <div class="card">7 the tag is - diy</div>
</div>
<div class="cards-container show" data-filter="easy">
  <div class="card">8 hthe tag is - easy</div>
</div>
<div class="cards-container show" data-filter="easy green">
  <div class="card">9 the tags are - easy green</div>
</div>

function isArrayEqual(a, b) {
    var arrA = a.join() // Array as String
    var arrB = b.join() // Array as String
    
    // Compare length of two string
    if (arrA.length != arrB.length) {
        return false
    }
    
    var totalA = 0
    var totalB = 0
    
    for (var i = 0; i < arrA.length; i++) {
        totalA += arrA.charCodeAt(i)
        totalB += arrB.charCodeAt(i)
    }
    
    // Array is same, if both total equal
    if (totalA == totalB) {
        return true
    }
}

我找到了一个解决方案,它查看每个数组的值,然后只显示在其数据属性中具有该值组合的卡片。 原始问题的问题,它只显示具有相同顺序值的卡片,第一个灵魂显示匹配值的任何卡片,而不是值的组合。

var checker = function(arr, target) {
    return target.every(function(v){
        return arr.includes(v);
    });
}

return checker(dataArray, selectedFilters);