需求場景:
- table 的列是由接口動態返回的;
- 列的篩選項就是數據的值,比如【姓名】這個字段總共有三個值,那么姓名這一列的篩選項就是這三個值本身;
- 當有一列篩選后,其他列的篩選項也要動態變化。
vxe-table 版本:4.9.14
完整代碼如下:
vue template 部分:
<vxe-tableref="vxeTableRef":data="state.tableData"height="100%"border@filter-change="handleFilterChange"><vxe-columnv-for="colOpt in columnsOptions":key="colOpt.field":field="colOpt.field":title="colOpt.title"align="center"resizablesortable:filters="colOpt.filters":filter-method="colOpt.filterMethod"/></vxe-table>
script 部分:
<script setup lang="ts">
// 其他代碼
const vxeTableRef = ref();const handleSearch = () => {// 獲取table數據部分的邏輯API(params).then((res: any) => {// ...state.tableData = data || [];if (state.tableData.length > 0) {// 在數據加載后重置所有篩選nextTick(() => {if (vxeTableRef.value) {vxeTableRef.value.clearFilter();}});}});
}// 下面是處理列篩選的邏輯
// 獲取篩選選項
const getColumnFilters = (column: string) => {// 使用 Map 來提高性能const uniqueMap = new Map();for (const row of state.tableData) {const value = row[column];if (!uniqueMap.has(value)) {uniqueMap.set(value, {label: value == null || value == "" ? "(空)" : String(value),value: value,checked: false});}}return Array.from(uniqueMap.values());
};// 創建篩選方法
const createFilterMethod = (column: string) => {return ({ value, row }: { value: any; row: any }) => {const cellValue = row[column];// 處理空值的情況if (value === null || value === "") {return cellValue === null || cellValue === "";}// 如果單元格值是數字,進行數字比較if (typeof cellValue === "number") {return cellValue === Number(value);}// 默認進行字符串比較return String(cellValue) === String(value);};
};// 數據是異步加載的,使用計算屬性來處理列配置
const columnsOptions = computed(() => {return state.columns.map(col => ({field: col,title: col,filters: getColumnFilters(col),filterMethod: createFilterMethod(col)}));
});// 處理篩選變化
const handleFilterChange = (params: any) => {// 獲取當前表格中可見的行數據const { filterList } = params;// 如果沒有篩選項,就刷新if (!filterList || filterList.length === 0) {handleSearch();}// 篩選已經應用,獲取處理后的可見數據const visibleData = vxeTableRef.value?.getTableData().visibleData || [];// 獲取當前被篩選的列,避免修改它們的篩選項const filteredColumns = new Set(filterList.map((item: any) => item.field));// 更新篩選狀態nextTick(() => {// 只更新未被篩選的列state.columns.forEach(column => {// 跳過當前正在篩選的列if (filteredColumns.has(column)) return;// 為此列生成新的篩選選項,但僅從可見數據中獲取const uniqueMap = new Map();for (const row of visibleData) {const value = row[column];if (!uniqueMap.has(value)) {uniqueMap.set(value, {label: value == null || value === "" ? "(空)" : String(value),value: value,checked: false});}}// 更新此列的篩選項if (vxeTableRef.value) {vxeTableRef.value.setFilter(column, Array.from(uniqueMap.values()));}});});
};
</script>
里面關鍵的一個點在于,vxe-table 篩選后的展示數據跟我們的源數據是分開的,所以篩選觸發的事件中,我們應該拿 visibleData 來做篩選項的動態處理。
由于邏輯可復用,所以記錄一下,需要用的時候直接copy就好了。