当前位置: 首页 > article >正文

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>


http://www.kler.cn/a/418910.html

相关文章:

  • PHP如何在MongoDB中使用正则表达式进行查询
  • Rust vs Java:后端开发应该选哪个?
  • 【C语言】扫雷游戏(一)
  • 搭建业务的性能优化指南
  • 2411rust,1.83
  • ffmpeg安装(windows)
  • flutter 解决webview加载重定向h5页面 返回重复加载问题
  • 电脑cpu带的字母代表啥
  • 牛客面经学习【2024/12/1】
  • 剪映自动批量替换视频、图片素材教程,视频批量复刻、混剪裂变等功能介绍
  • PDF版地形图矢量出现的问题
  • Linux下的root密码重置
  • Dockerfile打包部署
  • MYSQL 什么是内连接 外连接 左连接 右连接?及适用场景
  • C++11新增特性2
  • vue3typescript,shims-vue.d.ts中declare module的vue声明
  • C-操作符
  • Linux虚拟机安装nginx踩坑记录
  • 《UDS协议从入门到精通(UDS速查手册)》(完结撒花版)
  • Java之链表1
  • vue3+elPlus 选择框select 下拉数据过千条,页面卡顿,分页解决
  • Java中 HttpURLConnection 和 HttpClient 详解(初学者友好)
  • 【从零开始的LeetCode-算法】3208. 交替组 II
  • 【Git教程 之 版本控制】
  • 深入探讨SQL优化原理 - 增量查询和索引加速
  • JavaScript 高级教程:异步编程、面向对象与性能优化