Фильтровать на основе нескольких условий и нескольких массивов? - PullRequest
0 голосов
/ 14 июня 2019

У меня есть список продуктов в формате 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"]
        }
        ...
        ...
        ...
    ]
}

Как видите, есть styles, colors и sizes. И есть также элемент tags, который на самом деле состоит из всех трех предыдущих.

Мне нужно, чтобы кто-то мог фильтровать по нескольким выборкам. Например, если кто-то выберет стиль Low 1, а затем черный, то покажите им черные элементы в этом стиле. Но если они ТАКЖЕ выбирают белый, то покажите им белый ИЛИ черный, или оба. То же самое с выбором размера. Пример: 1 низкий элемент, черный или белый, И размер 5, или размер 6, или оба.

Наконец, несколько стилей должны быть выбраны одновременно, а также цвета и размеры должны выбираться без выбора стиля. Таким образом, приведенный выше пример, но затем добавьте другой стиль сверху, как стиль загрузки. Затем он должен вернуть продукты, которые соответствуют ВСЕМ критериям.

Это вообще выполнимо?

В настоящее время я делаю это так:

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 - это просто простое значение типа bool, которое позволяет vuejs показывать элемент на странице или нет, а this.selectedOptions - это массив, который динамически заполняется каждый раз, когда кто-либо добавляет / удаляет параметр внутри фильтра. Пример того, что он хотел бы:

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

Приведенный выше код фильтрации работает, но не надежно. Он возвращает все элементы, которые соответствуют любому из критериев, независимо от других выбранных фильтров. Если я изменю some на every, произойдет обратное, когда он попытается найти только элементы, имеющие красный И черный цвет. Или размер 5 И 6 и т. Д.

Я более или менее пытаюсь повторить фильтрацию на https://www.everlane.com/collections/mens-tees

Ответы [ 2 ]

1 голос
/ 14 июня 2019

Вы можете найти это полезным.

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;
}


  
    
      
        Style
Colors
Sizes
Additive filtering:

Products


  

Соответствующим битом является метод x, который является пересечением массива.

0 голосов
/ 14 июня 2019

Этот фильтр фактически открыт.

Но я думаю, что вы ищете что-то, где некоторые элементы И и другие ИЛИ

Итакесли пользователь выбирает размер , вы хотите отфильтровать их.

Но color - это вариант ||?

Если это так, я исправлю эту модель.Дайте мне знать.

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));
...