我有这样的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样式,然后选择黑色,则向他们显示该样式中的黑色项目。但是,如果他们也选择白色,则将它们显示为白色或黑色,或同时显示两者。与尺寸选择相同。示例:黑色,白色,AND尺寸5或6或两者都低的1件商品。
最后,应该一次选择多个样式,并且还应该选择颜色和大小,而不选择样式。所以上面的示例,但是然后在顶部添加另一个样式,例如Boot样式。然后,它将返回符合所有条件的产品。
这甚至可行吗?
目前我正在这样做:
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
是一个数组,每次有人在过滤器中添加/删除选项时,该数组就会动态填充。想要的示例:
this.selectedOptions = ["filter-style-Erving","filter-color-Black","filter-color-Brown","8","9"]
以上过滤代码有效,但不可靠。它返回与任何条件匹配的所有项目,而与其他选定过滤器无关。如果我将some
更改为every
,则会发生相反的情况,即尝试仅查找具有红色和黑色的项目。或5 AND 6尺寸,等等
我或多或少尝试在https://www.everlane.com/collections/mens-tees上复制过滤条件
答案 0 :(得分:1)
您可能会发现这很有用。
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
方法,它是数组的交集。
答案 1 :(得分:0)
此过滤器实际上是打开的。
但是我认为您正在寻找的东西中有些项目是 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));