基于多个条件和多个数组进行过滤?

Filter based on multiple conditions and multiple arrays?

我在 JSON 中有一个这样的产品列表:

{
    "products": [
        {
            "tags": ["filter-color-White", "filter-style-Low 1", "5", "6", "7", "8", "9", "10", "11", "12", "13"],
            "styles": ["filter-style-Low 1"],
            "colors": ["filter-color-White"],
            "sizes": ["5", "6", "7", "8", "9", "10", "11", "12", "13"]
        }, 
        {
            "tags": ["filter-color-Black", "filter-color-Red", "filter-color-Blue", "filter-style-Boot", "7", "8", "9", "12", "13"],
            "styles": ["filter-style-Boot"],
            "colors": ["filter-color-Black", "filter-color-Red", "filter-color-Blue"],
            "sizes": ["7", "8", "9", "12", "13"]
        }, 
        {
            "tags": ["filter-color-Black", "filter-color-Red", "filter-style-Gat", "7", "8", "9", "10", "11", "12", "13"],
            "styles": ["filter-style-Gat"],
            "colors": ["filter-color-Black", "filter-color-Red"],
            "sizes": ["7", "8", "9", "10", "11", "12", "13"]
        }
        ...
        ...
        ...
    ]
}

如您所见,有stylescolorssizes。还有一个 tags 项目,它实际上是由前面所有三个项目组成的。

我需要有人能够根据多个 select 离子进行过滤。例如,如果某人 select 是 Low 1 款式然后是黑色,则向他们展示该款式的黑色商品。但是,如果他们还 select 白色,则向他们展示白色或黑色,或两者兼而有之。与大小 select 离子相同。示例:低 1 件商品为黑色或白色,且尺寸为 5 号或 6 号,或两者兼而有之。

最后,应该 select 可以同时使用多种样式,并且颜色和尺寸也应该 select 可以 select 可以使用,而无需 select 编辑样式。所以上面的例子,然后在上面添加另一种风格,比如 Boot 风格。然后它应该 return 符合所有标准的产品。

这可行吗?

目前我是这样做的:

let filterOptions = this.selectedOptions;
this.products.forEach(product => {
  if (filterOptions.some(item => product.tags.includes(item))) {
    return product.visible = true;
  } else if(filterOptions.length == 0) {
    return product.visible = true;
  } else {
    return product.visible = false;
  }
})

其中 product.visible 只是一个简单的布尔值,它允许 vuejs 在页面上显示或不显示项目,this.selectedOptions 是一个数组,每次有人 adds/removes 时都会动态填充过滤器内的选项。它喜欢什么的例子:

this.selectedOptions = ["filter-style-Erving","filter-color-Black","filter-color-Brown","8","9"]

以上过滤代码有效但不可靠。它 return 包含符合任何条件的所有项目,而不考虑其他 selected 过滤器。如果我将 some 更改为 every,则会发生相反的情况,然后它会尝试仅查找具有红色和黑色的项目。或者 5 号和 6 号尺寸等。

我或多或少尝试在 https://www.everlane.com/collections/mens-tees

上复制过滤

这个过滤器实际上是打开的。

但我认为您正在寻找一些项目 AND 和其他 OR

因此,如果用户选择了 尺码,您想要过滤掉它们。

但是颜色是一个||选项?

如果是这样,我将更正为该型号。 让我知道。

const p = {
    "products": [
        {
            "tags": ["filter-color-White", "filter-style-Low 1", "5", "6", "7", "8", "9", "10", "11", "12", "13"],
            "styles": ["filter-style-Low 1"],
            "colors": ["filter-color-White"],
            "sizes": ["5", "6", "7", "8", "9", "10", "11", "12", "13"]
        }, 
        {
            "tags": ["filter-color-Black", "filter-color-Red", "filter-color-Blue", "filter-style-Boot", "7", "8", "9", "12", "13"],
            "styles": ["filter-style-Boot"],
            "colors": ["filter-color-Black", "filter-color-Red", "filter-color-Blue"],
            "sizes": ["7", "8", "9", "12", "13"]
        }, 
        {
            "tags": ["filter-color-Black", "filter-color-Red", "filter-style-Gat", "7", "8", "9", "10", "11", "12", "13"],
            "styles": ["filter-style-Gat"],
            "colors": ["filter-color-Black", "filter-color-Red"],
            "sizes": ["7", "8", "9", "10", "11", "12", "13"]
        }
    ]
};

const getFiltered = ( ({products}, filterValues) =>                                                
                        products.filter(p => Object.entries(p)
                                                   .flatMap(([k, v]) => v)
                                                   .some(entry => filterValues.includes(entry))));

console.log(getFiltered(p, ["5", "filter-style-Gat"]));

假设我们想要一些条件:

const p = {
  "products": [{
      "tags": ["filter-color-White", "filter-style-Low 1", "5", "6", "7", "8", "9", "10", "11", "12", "13"],
      "styles": ["filter-style-Low 1"],
      "colors": ["filter-color-White"],
      "sizes": ["5", "6", "7", "8", "9", "10", "11", "12", "13"]
    },
    {
      "tags": ["filter-color-Black", "filter-color-Red", "filter-color-Blue", "filter-style-Boot", "7", "8", "9", "12", "13"],
      "styles": ["filter-style-Boot"],
      "colors": ["filter-color-Black", "filter-color-Red", "filter-color-Blue"],
      "sizes": ["7", "8", "9", "12", "13"]
    },
    {
      "tags": ["filter-color-Black", "filter-color-Red", "filter-style-Gat", "7", "8", "9", "10", "11", "12", "13"],
      "styles": ["filter-style-Gat"],
      "colors": ["filter-color-Black", "filter-color-Red"],
      "sizes": ["7", "8", "9", "10", "11", "12", "13"]
    }
  ]
};

const getFiltered = (({ products }, {
  tags,
  styles,
  colors,
  sizes
}) => {
  // Filter size fully.
  return products.filter(({
      sizes: s
    }) => (sizes) ? s.some(size => sizes.includes(size)) : true)
    // Now color
    .filter(({
      colors: c
    }) => (colors) ? c.some(color => colors.includes(color)) : true)
    // style etc.
    .filter(({
      styles: s
    }) => (styles) ? s.some(style => styles.includes(style)) : true)

});

const filter = {
  sizes: ["6", "7"],
  colors: ["filter-color-Red"]
};

console.log(getFiltered(p, filter));

您可能会发现这很有用。

Vue.config.productionTip = false;
Vue.config.devtools = false;

new Vue({
  el: '#hook',
  template: '#app-template',
  data: () => ({
    data: [{
        styles: ["filter-style-Low 1"],
        colors: ["filter-color-White"],
        sizes: ["5", "6", "7", "8", "9", "10", "11", "12", "13"]
      },
      {
        styles: ["filter-style-Boot"],
        colors: ["filter-color-Black", "filter-color-Red", "filter-color-Blue"],
        sizes: ["7", "8", "9", "12", "13"]
      },
      {
        styles: ["filter-style-Gat"],
        colors: ["filter-color-Black", "filter-color-Red"],
        sizes: ["7", "8", "9", "10", "11", "12", "13"]
      }
    ],
    filters: {
      styles: [],
      colors: [],
      sizes: []
    },
    additiveFiltering: false
  }),
  computed: {
    products() {
      return this.data.map(product => ({
        ...product,
        tags: this.tags(product)
      }))
    },
    filteredProducts() {
      return this.products.filter(
        this.additiveFiltering
        ? p => this.x(this.filters.styles, p.styles).length
            || this.x(this.filters.colors, p.colors).length
            || this.x(this.filters.sizes, p.sizes).length
        : p => (!this.filters.styles.length
                || this.x(this.filters.styles, p.styles).length)
            && (!this.filters.colors.length
                || this.x(this.filters.colors, p.colors).length)
            && (!this.filters.sizes.length
                || this.x(this.filters.sizes, p.sizes).length)
            
      )
    },
    allStyles() {
      return this.getAll('styles')
    },
    allColors() {
      return this.getAll('colors')
    },
    allSizes() {
      return this.getAll('sizes')
    }
  },
  methods: {
    tags(product) {
      return [].concat(product.styles, product.colors, product.sizes)
    },
    logger(obj) {
      return JSON.stringify(obj, null, 2)
    },
    getAll(prop) {
      return [ ...new Set([].concat.apply([], this.data.map(item => item[prop])))]
    },
    x(arr1, arr2) {
      return arr1.filter(val => arr2.includes(val))
    }
  }
})
ul>li>span {
  background-color: #333;
  color: white;
  padding: 0 5px 2px;
  margin: 0 5px 5px 0;
  border-radius: 3px;
  font-variant: all-petite-caps;
  font-family: monospace;
}
.filters {
  display: flex;
}
.filters > div {
  flex: 1;
}
.filters > div:last-child {
  columns: 2;
}
.filters > div:last-child div{
  column-span: all;
}
.filters label {
  display: block;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  margin: 5px;
  border: 1px solid transparent;
  padding: 1rem;
}
.selected {
  background-color: #f5f5f5;
  border-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/template" id="app-template">
  <div id="app">
    <div class="filters">
      <div>
        <div>Style</div>
        <label v-for="style in allStyles" :key="style">
          <input type="checkbox" v-model="filters['styles']" :value="style">
          {{style}}
        </label>
      </div>
      <div>
        <div>Colors</div>
        <label v-for="color in allColors" :key="color">
          <input type="checkbox" v-model="filters['colors']" :value="color">
          {{color}}
        </label>
      </div>
      <div>
        <div>Sizes</div>
        <label v-for="size in allSizes" :key="size">
          <input type="checkbox" v-model="filters['sizes']" :value="size">
          {{size}}
        </label>
      </div>
    </div>
    Additive filtering: <input type="checkbox" v-model="additiveFiltering">
    <h3>Products</h3>
    <ul>
      <li v-for="(product, key) in products" :key="key" 
      :class="{selected: filteredProducts.includes(product)}">
        <span v-for="tag in product.tags" :key="tag" v-text="tag"></span>
      </li>
    </ul>
    <pre v-text="{filters}"></pre>
  </div>
</script>
<div id="hook"></div>

相关位是x方法,是数组交集。