【问题标题】:For filtering using data-attributes, In JS how do I match 2 arrays that have the same words but in a different order?对于使用数据属性进行过滤,在 JS 中如何匹配具有相同单词但顺序不同的 2 个数组?
【发布时间】:2021-02-24 23:03:20
【问题描述】:

我正在尝试创建一个使用数据属性的过滤器系统,如果选择的项目与元素数据属性的顺序匹配,我可以让它工作,例如:选择的项目 {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>

【问题讨论】:

    标签: javascript arrays sorting custom-data-attribute


    【解决方案1】:

    根据评论更新

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

    变化:

        // 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的数组是否包含elements属性。

    变化

      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>

    【讨论】:

    • 上述解决方案适用于显示与所选按钮匹配的所有元素,但如何仅显示与所选按钮完全匹配的元素? eg:我选择Cheap and Big,只显示属性数组中具有Cheap和Big的元素,然后隐藏所有其他元素。所以一个只有廉价属性的元素会被隐藏。
    • @Nathan 答案已更新以反映这些要求。更改是拆分每个过滤器项以创建一个数组,然后使用Array.prototype.every 仅获取符合所有条件的项。
    【解决方案2】:
    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
        }
    }
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2022-01-19
        • 2021-05-24
        • 2022-01-08
        • 2021-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-30
        • 1970-01-01
        相关资源
        最近更新 更多