表头筛选改成了el-select实现,代码cv可以直接用 就是下图效果

效果图:

vxe-table实现表头筛选自定义_vxe-table

其中核心是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结构如图

vxe-table实现表头筛选自定义_vxe-table_02

其中包含了已选中的数组,最终通过filterMethod实现筛选

清空搜索就是$panel.resetFilter(); 应该会触发filterResetMethod



以上内容全是个人猜测加试出来的,没看源码,功能仅供参考

环境vue2和vxe3.9