基于多个条件和多个数组进行过滤?
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"]
}
...
...
...
]
}
如您所见,有styles
、colors
和sizes
。还有一个 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 号尺寸等。
上复制过滤
这个过滤器实际上是打开的。
但我认为您正在寻找一些项目 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
方法,是数组交集。
我在 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
项目,它实际上是由前面所有三个项目组成的。
我需要有人能够根据多个 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 号尺寸等。
这个过滤器实际上是打开的。
但我认为您正在寻找一些项目 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
方法,是数组交集。