表头筛选改成了el-select实现,代码cv可以直接用 就是下图效果
效果图:
其中核心是filters,filter-render,columns属性
<vxe-column
v-for="column in columns"
:key="column.field"
:field="column.field"
:title="column.title"
:formatter="column.formatter"
:width="column.width"
:filter-render="{ name: column.filters.render }"
:filters="column.filters.data"
></vxe-column>
columns: [
{
field: "ect",
title: "ECT",
formatter: null,
width: null,
filters: {
data: [{ data: { vals: [], sVal: "" } }],
render: "AdvancedFilterRenderNew",
},
}]
根据官方文档引入的话应该有以下文件,其中advancedAaa就是自定义组件。
VxeUI.renderer.add('AdvancedFilterRenderNew')应该和columns.filters.render的对应上
理论上可以实现无限丰富的表头筛选,只要VxeUI.renderer.add添加了就可以使用
advanced.table.renderer.jsx
import { VxeUI } from 'vxe-pc-ui';
import advancedAaa from '@core/components/ui/big-table/a.vue';
VxeUI.renderer.add('AdvancedFilterRenderNew', {
renderFilter(h, renderOpts, params) {
return <advancedAaa params={ params }></advancedAaa>;
},
// 是否显示底部按钮,使用自定义的按钮
showFilterFooter: false,
// 筛选数据方法
filterMethod(params) {
const { option, row, column } = params;
const { vals } = option.data;
const cellValue = row[column.field];
let columnValue = column.formatter
? column.formatter.call(this, { 'cellValue': String(cellValue) })
: String(cellValue);
if (!columnValue || columnValue === 'null') {
columnValue = '(Blanks)';
}
return vals.includes(columnValue);
},
// 重置数据方法
filterResetMethod(params) {
const { options } = params;
options.forEach((option) => {
option.data = { vals: [] };
});
}
});
这是我根据官方提供的示例组件改造的,其中应该有些用不到的代码,请注意自行甄别
a.vue
<template>
<div v-if="currOption" class="my-filter-content">
<div class="my-fc-select">
<Select
ref="mySelect"
transfer="true"
:popper-append-to-body="false"
multiple
default-first-option
v-model="selectValue"
filterable
style="width: 200px"
placeholder=""
popper-class="custom-dropdown"
>
<template slot="prefix">
<img
src="@/assets/icons/search.png"
style="width: 1.2rem; height: 1.2rem; margin-top: 0.2rem"
/></template>
<Option
v-for="item in columnValList"
:key="item.value"
:label="item.value"
:value="item.value"
>
</Option>
</Select>
</div>
<div class="my-fc-footer">
<vxe-button @click="resetFilterEvent">Clear</vxe-button>
<vxe-button status="primary" @click="confirmFilterEvent"
>Apply</vxe-button
>
</div>
</div>
</template>
<script>
import XEUtils from "xe-utils";
import { Select, Option } from "element-ui";
export default {
name: "advanced-aaa",
props: {
params: Object,
},
components: {
Select,
Option,
},
data() {
return {
currOption: null,
isCheckedAll: false,
allValList: [],
columnValList: [],
hasBlankItem: false,
blankItemChecked: false,
selectValue: [],
};
},
// computed: {
// aDouble: this.columnValList,
// },
// computed: {
// fullName() {
// return `${this.columnValList}`; // 计算全名
// },
// },
methods: {
changeVheckbox(val, val2) {
console.log(val, this.columnValList, "val,val2");
},
load() {
const { params } = this;
if (params) {
const { $table, column } = params;
const { fullData } = $table.getTableData();
// excel是没回传文本过滤条件的,这里还是回传了,如果不需要可以sVal不作为filter值传
const option = column.filters[0];
console.log(
JSON.parse(JSON.stringify(column.filters)),
"optionoptionoption"
);
const { vals } = option.data;
// 由于是多选列表,要增加选中状态处理,别忘了处理全部选中状态
let isCheckedAll = true;
// excel逻辑是取上一个过滤后的渲染数据,而不是全量数据,增加了特殊处理
let visibleData = fullData;
if ($table.getCheckedFilters().length > 0) {
// 当filters长度是1,且是当前列时,不处理
if (
$table.getCheckedFilters().length === 1 &&
$table.getCheckedFilters()[0].field === column.field
) {
visibleData = fullData;
} else {
$table.getCheckedFilters().forEach((filter) => {
// if (filter.field !== column.field) {
// visibleData = visibleData.filter(item => filter.datas[0].vals.includes(item[filter.field]));
// }
console.log(visibleData, "visibleData 11");
visibleData = visibleData.filter((item) => {
let itemVal = filter.column.formatter
? filter.column.formatter.call(this, {
cellValue: item[filter.field],
})
: item[filter.field];
if (!itemVal || itemVal === "null") {
itemVal = "(Blanks)";
}
console.log(
filter.datas[0].vals,
itemVal,
"filter.datas[0].vals"
);
return filter.datas[0].vals.includes(String(itemVal));
});
console.log(visibleData, "visibleData 22");
});
}
}
// 从数据中抽取当前列的数据,去重
// 如果需要排序在这里处理
// formatter要特殊处理,否则列表筛选值不是预期值
const colValList = Object.keys(
XEUtils.groupBy(visibleData, column.field)
).map((val) => {
const sVal = column.formatter
? column.formatter.call(this, { cellValue: val })
: val;
console.log(sVal, "sVal");
if (!sVal || sVal === "null") {
this.hasBlankItem = true;
}
let checked = true;
if (vals.length) {
if (vals.includes("(Blanks)") && (!sVal || sVal === "null")) {
checked = true;
this.blankItemChecked = true;
} else {
checked = vals.includes(sVal);
}
} else {
this.blankItemChecked = true;
}
isCheckedAll = isCheckedAll && checked;
return {
checked: checked,
value: sVal,
};
});
// 使用 splice() 修改原数组,删除 value 为 null 的项
for (let i = colValList.length - 1; i >= 0; i--) {
console.log("nullnull 111");
if (colValList[i].value === "null") {
console.log("nullnull");
colValList.splice(i, 1); // 删除当前索引的元素
}
}
this.isCheckedAll = isCheckedAll;
this.currOption = option;
this.allValList = colValList;
this.columnValList = colValList;
console.log(colValList, "colValList");
}
},
// 输入框搜索
searchEvent() {
const option = this.currOption;
if (option) {
this.columnValList = option.data.sVal
? this.allValList.filter(
(item) =>
item.value
.toLowerCase()
.indexOf(option.data.sVal.toLowerCase()) > -1
)
: this.allValList;
}
},
// 全选
changeAllEvent() {
this.columnValList.forEach((item) => {
item.checked = this.isCheckedAll;
});
this.blankItemChecked = this.isCheckedAll;
},
// 确认按钮
confirmFilterEvent() {
const { params } = this;
const option = this.currOption;
if (params && option) {
const { data } = option;
const { $panel } = params;
// data.vals = this.columnValList
// .filter((item) => item.checked)
// .map((item) => item.value);
// if (this.blankItemChecked) {
// data.vals.push("(Blanks)");
// }
console.log(this.selectValue, "this.selectValue");
if (
this.selectValue.length === 0 ||
(this.selectValue.length === 1 && this.selectValue[0] === "null")
) {
this.resetFilterEvent();
}
data.vals = this.selectValue.map((item) => item);
console.log(data.vals, "data.vals");
// option包含选中数据
// params包含$panel
console.log(
option,
params,
this.columnValList,
"option, params, this.columnValList"
);
$panel.changeOption(null, true, option);
$panel.confirmFilter();
}
},
// 清空按钮
resetFilterEvent() {
const { params } = this;
if (params) {
const { $panel } = params;
$panel.resetFilter();
}
},
},
watch: {
"props.params"() {
this.load();
},
},
created() {
this.load();
const { params } = this;
this.selectValue = params.column.filters[0].data.vals;
console.log(params.column.filters[0].data.vals, "propsparams");
},
mounted() {
this.$refs.mySelect.focus();
},
};
</script>
<style lang="scss" scoped>
.my-filter-content {
padding: 10px;
user-select: none;
height: 23rem;
display: flex; /* 启用 flexbox */
flex-direction: column; /* 设置主轴方向为竖直方向 */
::v-deep .el-select__tags {
padding-left: 1.3rem;
}
.my-fc-select {
padding: 10px;
}
.my-fc-footer {
text-align: right;
margin-top: auto;
}
.my-fc-footer button {
padding: 0 15px;
margin-left: 15px;
}
}
</style>
$panel.changeOption(null, true, option);
$panel.confirmFilter();
确认的时候调用这两个方法,会触发advanced.table.renderer.jsx文件中的 filterMethod方法
option结构如图
其中包含了已选中的数组,最终通过filterMethod实现筛选
清空搜索就是$panel.resetFilter(); 应该会触发filterResetMethod
以上内容全是个人猜测加试出来的,没看源码,功能仅供参考
环境vue2和vxe3.9