antd table 自定义表头过滤表格内容
注意:该功能只能过滤可一次性返回全部数据的表格,通过接口分页查询的请自主按照需求改动哈~
实现步骤:
1.在要过滤的列表表头增加过滤图标,点击图标显示浮窗
2.浮窗内显示整列可选选项,通过勾选单选或者全选、搜索框来过滤表格内容
效果如下:
表格页面index.vue:
<template>
<div>
<a-table :columns="column" :data-source="data" @change="change">
<template v-for="(col, index) in column">
<span :slot="col.slots.title" v-if="col.filterable" :key="index">
<!-- -->
<popover-filter
:ref="'popover_' + col.slots.title"
:key="col.dataIndex"
:label="col.dataIndex"
:field="col.dataIndex"
:shoppingType="0"
:filters="col.filtersList"
@filter="handleFilterTable"
/>
<span slot-scope="text, record">{{ text }}{{ record }}</span>
</span>
</template>
</a-table>
</div>
</template>
<script>
import PopoverFilter from "./popover-filter.vue";
export default {
components: {
PopoverFilter
},
data() {
return {
column: [],
data: [],
filters: {},
allData: []
};
},
mounted() {
const columns = [
{
title: "序号",
dataIndex: "id",
customRender: (text, row, index) => {
return index + 1;
},
width: 86
},
{
//title: "Name",
dataIndex: "name",
width: "20%",
slots: { title: "name" },
filterable: true,
onFilter: function(value, record) {
console.log("value", value);
return record.name.indexOf(value) != -1;
}
},
{
//title: "Gender",
dataIndex: "gender",
filters: [
],
width: "20%",
filterable: true,
slots: { title: "gender" }
},
{
title: "Email",
dataIndex: "email"
}
];
this.column = columns;
this.data = [
{ name: "jone ke", gender: "Male", email: "23293238@qq.com" },
{ name: "meary", gender: "Male1", email: "23293238@qq.com" },
{ name: "lu xi", gender: "Doke", email: "23293238@qq.com" },
{ name: "jiner", gender: "Doke1", email: "23293238@qq.com" },
{ name: "geng", gender: "Doke1", email: "23293238@qq.com" }
];
this.allData = [...this.data];
//要显示过滤的列,dataIndex
let filterList = ["name", "gender"];
this.column.forEach(item => {
if (filterList.includes(item.dataIndex)) {
//获取每列所有数据,去除重复项
item.filtersList = [...new Set(this.data.map(e => e[item.dataIndex]))];
}
});
//console.log("this.column", this.column);
},
methods: {
change(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
},
handleFilterTable(checkedList, field, label) {
console.log(checkedList, field, label);
this.filters[field] = checkedList;
this.data = [...this.allData];
Object.keys(this.filters).forEach(e => {
this.data = this.data.filter(i =>
this.filters[e].length > 0 ? this.filters[e].includes(i[e]) : true
);
});
},
changeFilter(checkedList, field) {
console.log(checkedList, field);
//this.filterInfo[this.typeValue][field] = checkedList;
}
}
};
</script>
<style lang="less" scoped></style>
浮窗组件popover-filter.vue:
<template>
<div class="filter-column">
<!-- visible=true面板显示时或者有勾选项时icon图标高亮 -->
<div
class="popover-title"
:class="{ 'popover-title-active': visible || this.selected.length }"
>
<span>{{ label }}</span>
<span class="caret-wrapper">
<i class="sort-caret ascending"></i>
<i class="sort-caret descending"></i>
</span>
<a-popover
overlayClassName="popover"
width="190"
ref="filter"
popper-class="m-popper"
v-model="visible"
trigger="click"
:overlayStyle="{ width: '200px' }"
>
<span class="filter-icon" @click.stop="handleClick"></span>
<template slot="content">
<a-input
placeholder="请输入关键词"
suffix-icon="a-icon-search"
size="small"
@input="handleFilter($event)"
v-model="keyWord"
>
<a-icon slot="prefix" type="search" />
</a-input>
<div class="popover-filter" v-loading="loading">
<a-checkbox
:indeterminate="indeterminate"
:checked="checkAll"
@change="handleCheckAllSource"
>全选{{ filters.length ? `(${filters.length})` : "" }}
</a-checkbox>
<a-checkbox-group
v-model="checkedValue"
class="popover-checkbox-group"
@change="handleCheck"
>
<a-checkbox
v-for="item in filterOptions"
:key="item"
:value="item"
>
<span>{{ item }}</span>
</a-checkbox>
</a-checkbox-group>
</div>
<div class="popover-btn-group">
<a-button
type="text"
size="small"
class="popover-btn popover-btn-reset"
:class="{ 'popover-btn-active': checkedValue.length > 0 }"
@click="handleReset"
>重置</a-button
>
<a-button
type="primary"
size="small"
class="popover-btn"
@click="handleSearch"
>确定</a-button
>
</div>
</template>
</a-popover>
</div>
</div>
</template>
<script>
export default {
components: {},
props: {
label: {
type: String,
default: ""
},
field: {
type: String,
default: ""
},
shoppingType: {
type: Number,
default: 0
},
filters: {
type: Array,
default: () => []
}
},
data() {
return {
// 是否显示筛选框
showFilter: false,
interval: null,
keyWord: "",
loading: false,
// 当前选择项
checkedValue: [],
selected: [],
// 选择项列表
options: [],
filterOptions: [],
checkAll: false,
indeterminate: false,
visible: false
};
},
watch: {
showFilter: {
handler(val) {
if (val) {
this.getList();
} else {
this.keyWord = "";
}
}
}
},
created() {},
mounted() {
this.options = this.filters;
this.filterOptions = [...this.options];
},
methods: {
handleClick() {
//this.filterOptions = [...this.options];
//this.$emit("click");
this.visible = !this.visible;
if (this.visible) {
//面板显示时回显勾选
this.checkedValue = [...this.selected];
//显示全部勾选项
this.getList();
//清空搜索框
this.keyWord = "";
//判断全选勾选框状态
this.checkAll = this.checkedValue.length === this.filterOptions.length;
this.indeterminate =
this.checkedValue.length > 0 &&
this.checkedValue.length < this.filterOptions.length;
}
},
handleFilter() {
if (this.interval) {
clearTimeout(this.interval);
}
this.interval = setTimeout(() => {
this.filterOptions = this.options.filter(ele =>
ele.toLowerCase().includes(this.keyWord.trim().toLowerCase())
);
console.log("搜索");
clearTimeout(this.interval);
this.interval = null;
}, 1000);
},
getList() {
// this.loading = true;
// const params = {
// shoppingType: this.shoppingType,
// fieldStr: this.field,
// };
// this.axios
// .post(`${this.$baseUrl}/mds/web/shopping/getCartSelect`, params)
// .then((res) => {
// this.loading = false;
// if (res.data.code == "200") {
// console.log("来源", res);
// this.options = res.data.data || [];
// this.filterOptions = [...this.options];
// this.selected = this.selected.filter(ele => this.options.includes(ele));
// this.checkedValue = [...this.selected];
// this.$emit('changeFilter', this.checkedValue, this.field);
// }
// })
// .catch((res) => {
// this.loading = false;
// });
this.filterOptions = [...this.options];
},
handleCheck(val) {
console.log("val", val, this.checkedValue);
const count = val.length;
this.checkAll = count === this.filterOptions.length;
this.indeterminate = count > 0 && count < this.filterOptions.length;
},
handleCheckAllSource() {
if (this.checkedValue.length == this.filterOptions.length) {
this.checkedValue = [];
this.checkAll = false;
} else {
this.checkedValue = this.filterOptions;
this.checkAll = true;
}
},
handleReset() {
this.checkedValue = [];
this.checkAll = false;
this.indeterminate = false;
this.keyWord = "";
this.filterOptions = [...this.options];
/* this.$refs.filter.doClose();
this.$emit("filter", this.checkedValue, this.field); */
},
handleSearch() {
this.selected = [...this.checkedValue];
this.visible = false;
this.$emit("filter", this.checkedValue, this.field, this.label);
},
close() {
this.$refs.filter.doClose();
}
}
};
</script>
<style lang="less" scoped>
.filter-column {
.caret-wrapper {
width: 10px;
margin: 0 2px 0 8px;
.sort-caret {
left: 0;
}
}
.popover-title::after {
display: none;
}
.filter-icon {
width: 22px;
height: 22px;
display: inline-block;
background: url("../../assets/filter-default.svg") 50% no-repeat;
position: absolute;
top: 50%;
transform: translateY(-50%);
margin-left: 4px;
cursor: pointer;
&:hover {
background: url("../../assets/filter.svg") 50% no-repeat;
background-color: #d3dbea;
border-radius: 2px;
}
}
.popover-title-active .filter-icon {
background: url("../../assets/filter.svg") 50% no-repeat !important;
background-color: #d3dbea !important;
border-radius: 2px;
}
}
</style>
<style>
.popover .ant-popover-inner-content {
padding: 12px;
}
.popover-filter {
margin: 8px -12px;
padding: 4px 12px;
border-top: 1px solid #dee2ed;
border-bottom: 1px solid #dee2ed;
max-height: 200px;
overflow-y: auto;
}
.popover-filter .ant-checkbox-wrapper {
margin-left: 0;
width: 100%;
margin-bottom: 4px;
}
.popover-filter .popover-checkbox-group .ant-checkbox-wrapper {
margin-left: 0;
width: 100%;
margin-bottom: 4px;
}
.popover-btn-group {
display: flex;
justify-content: space-between;
}
</style>