在此之前,我相信很多时候开发都会遇到这样的需求:一组条件,一个列表,多条件组合,列表显示不同的结果。
以前在我做mes系统的时候,这些事情都是交给后端去做的,因为业务需求需要显示实时最新的数据结果,
所以前端把条件通过post请求传给服务端,服务给出最新的结果。
那时候我好奇的问过后端的同事,是怎么实现这种条件判断然后去做查询,答案是if判断,
如果这种事放在前端来做,那估计通常是这样的
if(conditionA && conditionB && !conditionC)
{
this.tableData=dataSource.filter(ele=>{
ele.propertyA==conditionA && ele.propertyB==conditionB && ele.propertyC!=conditionC)
}
else if(conditionA && !conditionB && conditionC)
{
//...一些操作
}
else if(!conditionA && conditionB && conditionC)
{
//...一些操作
}
else .......略
基本上最坏的情况就是这样,假设有3个条件,那就会有8种不同条件判断。
abc
ab!c
a!bc
a!b!c
!abc
!a!bc
!ab!c
!a!b!c
好嘛,也就3个条件,8个就8个吧。
有的人就会这样傻乎乎的把情况列出来然后写8个判断
但是条件如果多起来,这就好玩了
这得有多少相似代码?实现这么个筛选可能就得成百上千行?
这我想想就头疼,写的时候头疼,日后维护头更疼
为了避免这种尴尬的情况,那必须优雅一点。
一开始我也自己去思考过,如何去实现低代码高质量
可惜我太菜了,没想出来,最后还是看到某位大佬写的…
下面的这串代码最初版本似乎是爆栈上某位大佬写的(呃…时间有点久,忘了)
export function multiFilter(array, filters) {
const filterKeys = Object.keys(filters)
// 过滤所有元素传递标准
return array.filter((item) => {
// 动态验证所有的过滤标准
return filterKeys.every((key) => {
//忽略当过滤器是空的
if (!filters[key] || !filters[key].length) return true
return !!~filters[key].indexOf(item[key])
})
})
}
这串代码可以说
既然大佬都出手了,那我们这些菜鸡直接用就完事了,还费那么多头发干啥?
不过要注意的是方法传入的filters是一个对象,算是需要用到的筛选条件的组合,
但是每个属性也是个数组并且数组只能有一个元素。
使用vue+element UI 大概就可以这样
<template>
<div class="container">
<div class="filter_box">
<el-select v-model="filterOption.workYear" placeholder="工龄" clearable @change="filterList" multiple :multiple-limit="1">
<el-option
v-for="(item, index) in wyOpt"
:key="index"
:label="item"
:value="item"
>
</el-option>
</el-select>
<el-select v-model="filterOption.age" placeholder="年龄" clearable @change="filterList" multiple :multiple-limit="1">
<el-option v-for="(item, index) in ageOpt" :key="index" :label="item.label" :value="item.value"> </el-option>
</el-select>
<el-select v-model="filterOption.dept" placeholder="部门" clearable @change="filterList" multiple :multiple-limit="1">
<el-option v-for="(item, index) in deptOpt" :key="index" :label="item.label" :value="item.value"> </el-option>
</el-select>
</div>
<div class="table_box">
<el-table :data="datalist">
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="age" label="年龄"></el-table-column>
<el-table-column prop="gender" label="性别"></el-table-column>
</el-table>
</div>
</div>
</template>
js部分
data(){
return{
filterOption: {
age: [],
name: [],
gender: [],
workType: [],
workYear: [],
dept:[]
},
ageOpt: [],
deptOpt:[{
label:'研发',value:'dev'},{
label:'市场',value:'market'
}],
wyOpt:[1,2,3,4,5],
},
//源数据
source:[],
datalist: []
}
methods: {
filterList (e) {
this.datalist = multiFilter(this.source, this.filterOption)
}
},
这里仅当demo举例子,所以就偷个懒用element的多选下拉框,但是只允许选择一个,其他模样的筛选控件也是一个道理
v-model直接绑定到filterOption,change事件直接绑定同一个。
这样就简单实现动态条件筛选了,而且也没有辣么多的代码,一句话搞定
另外补充一下,上述multiFilter方法其实存在点问题,有点类似“模糊筛选”。
举个例子,你筛选条件是’滞后’,但是数据中的字段有:‘滞后’,‘严重滞后’
那么就会把‘滞后’,‘严重滞后’都筛选出来,因为用的是indexOf()
根据我的业务需要,我稍作修改
export function multiFilter(array, filters) {
const filterKeys = Object.keys(filters)
// 过滤所有元素传递标准
return array.filter((item) => {
// 动态验证所有的过滤标准
return filterKeys.every((key) => {
//忽略当过滤器是空的
if (!filters[key] || !filters[key].length) return true
// return !!~filters[key].indexOf(item[key])
return filters[key] == item[key]
})
})
}
这样就是准确结果
.
.
.
.
如有错误,欢迎大佬赐教(__)