vue+element+el-table 实现所有表格列筛选

最近在使用element+table组件开发后台过程中,接到一个需求,给所有表格加上列筛选功能,按大家正常的思路;肯定是每个页面加一下,通过v-if/v-show控制一下列的显示隐藏。

我这里的实现是统一处理,不管你有几个列,前提是有封装过el-tabel组件,所有表格都用了它,比如以下代码:(这个是我修改之前的代码)

<template>
    <div>
        <el-table
                element-loading-text="加载中"
                :row-key='rowKey'
                :expand-row-keys="expandRowKeys"
                @expand-change="expandChange"
                @selection-change="selectionChange"
                fit
                highlight-current-row
                header-cell-class-name="global_table_header"
                @sort-change='sort'
                :data="tableData"
                :border="border"
                v-loading="loading"
                class="global_table">
            <slot />
        </el-table>
        <div class="global_table_pagination">
            <el-pagination
                    @size-change="handleSizeChange"
                    v-if="pages"
                    background
                    layout="total, prev, pager, next, jumper"
                    :total="pages"
                    :page-sizes="[1, 3, 5, 8]"
                    :page-size="pageSize"
                    :current-page="currentPage"
                    @current-change="changePage">
            </el-pagination>
        </div>
    </div>
</template>

<script lang="ts">
    import {Vue, Prop, Component} from 'vue-property-decorator'

    @Component
    export default class extends Vue {
        @Prop({ required: true }) private tableData: any
        @Prop({ default: false }) private loading?: boolean
        @Prop({ required: false }) private pages?: number
        @Prop({ default: 10 }) private pageSize?: number
        @Prop({ default: 1 }) private currentPage?: number
        @Prop({ default: false }) private border?: boolean
        @Prop({ required: false }) private rowKey?: any
        @Prop({ required: false }) private expandRowKeys?: any[]

        protected changePage(page: number) {
            this.$emit('changePage', page)
        } 
        protected sort(value: any) {
            this.$emit('sort', value)
        }
        protected expandChange(row: any, expandedRows: any) {
            this.$emit('expandChange', row, expandedRows)
        }
        protected selectionChange(val: any[]) {
            this.$emit('selectionChange', val)
        }
        protected handleSizeChange(val:any) {
            console.log(`每页 ${val} 条`);
            this.pageSize = val;    //动态改变
        }
        protected handleCurrentChange(val:any) {
            console.log(`当前页: ${val}`);
            this.currentPage = val;
        }

    }
</script>

<style lang="scss" scoped>

</style>

然后在页面调用,代码如下:


<g-table :table-data="tableData">
<el-table-column></el-table-column>
...
</g-table>

import GTable from "@/components/Table/index.vue";
@Component({
  components: {
    GTable
  },
})

当我要给所有表格,增加列筛选功能时,还是有一点难度的,具体过程就不描述了,反正保持原有排序、翻页、搜索等功能的正常使用,见代码注释把:

<template>
  <div>
    <i @click="cellDialog = true" class="el-icon-set-up setting"></i>
    <g-dialog width="450px" @close="cellDialog = false" :show="cellDialog" title="筛选列">
      <div style="margin-top:-20px">
        <div style="margin-bottom:5px">
          <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
        </div>
        <div>
          <el-checkbox-group @change="handleCheckedCitiesChange" v-model="checkList">
            <el-checkbox class="column_label" :label="index" v-for="(item,index) in columnsList" :key="index">{{item.componentOptions.propsData.label?item.componentOptions.propsData.label:'第'+(index+1)+'列'}}</el-checkbox>
          </el-checkbox-group>
        </div>
        <div class="global_dialog_btn">
          <el-button @click="cellDialog = false">取消</el-button>
          <el-button type="primary" @click="setTable()">保存</el-button>
        </div>
      </div>
    </g-dialog>
    <el-table v-if="isTable" v-loading="loading" :default-sort="sort_default" element-loading-text="加载中" :row-key='rowKey' :expand-row-keys="expandRowKeys" @expand-change="expandChange" @selection-change="selectionChange" fit highlight-current-row header-cell-class-name="global_table_header" @sort-change='sort' :data="tableData" :border="border" class="global_table">
      <slot v-if="!isDefault" name="diy" />
      <slot v-else />
    </el-table>
    <div class="global_table_pagination">
      <el-pagination @size-change="handleSizeChange" v-if="pages" background layout="total, prev, pager, next, jumper" :total="pages" :page-sizes="[1, 3, 5, 8]" :page-size="pageSize" :current-page="currentPage" @current-change="changePage">
      </el-pagination>
    </div>
  </div>
</template>

<script lang="ts">
import { Vue, Prop, Component, Watch } from "vue-property-decorator";
import GDialog from "@/components/Dialog/index.vue";
import { set } from "js-cookie";

@Component({
  components: {
    GDialog,
  },
})
export default class extends Vue {
  @Prop({ required: true }) private tableData: any;
  @Prop({ default: false }) private loading?: boolean;
  @Prop({ required: false }) private pages?: number;
  @Prop({ default: 10 }) private pageSize?: number;
  @Prop({ default: 1 }) private currentPage?: number;
  @Prop({ default: false }) private border?: boolean;
  @Prop({ required: false }) private rowKey?: any;
  @Prop({ required: false }) private expandRowKeys?: any[];

  protected changePage(page: number) {
    this.$emit("changePage", page);
  }
  protected sort(value: any) {
    this.$emit("sort", value);
  }
  protected expandChange(row: any, expandedRows: any) {
    this.$emit("expandChange", row, expandedRows);
  }
  protected selectionChange(val: any[]) {
    this.$emit("selectionChange", val);
  }
  protected handleSizeChange(val: any) {
    console.log(`每页 ${val} 条`);
    this.pageSize = val; //动态改变
  }
  protected handleCurrentChange(val: any) {
    console.log(`当前页: ${val}`);
    this.currentPage = val;
  }

  beforeUpdate(){
    this.setSlot()
  }

  ///////////////////////表格筛选/////////////////////
  //全选
  checkAll = false;
  isIndeterminate = true;
  //是否渲染表格
  isTable = true;
  //是否显示筛选器
  cellDialog = false;
  //已选中筛选项
  checkList: any = new Array();
  //所有列
  columnsList: any = new Array();
  //是否默认
  isDefault = true;
  //当前列
  _default: any = new Array();
  //排序继承
  sort_default = { prop: "AAA", order: "descending" };
  //全选事件
  handleCheckAllChange(val: boolean) {
    let _options: any = [];
    this.columnsList.forEach((item: any, index: number) => {
      _options.push(index);
    });
    this.checkList = val ? _options : [];
    this.isIndeterminate = false;
  }
  handleCheckedCitiesChange(value: any) {
    let checkedCount = value.length;
    this.checkAll = checkedCount === this.columnsList.length;
    this.isIndeterminate =
      checkedCount > 0 && checkedCount < this.columnsList.length;
  }
  //读取缓存 暂时先这样
  columnCache = JSON.parse(localStorage.getItem("my_column") || "[]");
  //记录缓存
  addCache(checkids: string) {
    this.columnCache.forEach((item: any, index: number) => {
      if (item.name === location.hash) {
        this.columnCache.splice(index, 1);
        return false;
      }
    });
    this.columnCache.push({
      name: location.hash,
      value: checkids,
    });
    localStorage.setItem("my_column", JSON.stringify(this.columnCache));
  }
  //设置视图
  setSlot(){
    if (!this.isDefault) {
      //设置列
      this.$slots.diy = this._default;
    }
  }
  
  //监听数据源改变
  @Watch("tableData")
  getTableData() {
    console.log(this)
    // 找出排序对象名
    this.sort_default = { prop: "AAA", order: "descending" };
    if ((this.$parent as any).searchKey.sort) {
      Object.keys((this.$parent as any).searchKey.sort).forEach((item: any) => {
        this.sort_default.prop = item;
        this.sort_default.order =
          (this.$parent as any).searchKey.sort[item] == 4
            ? "ascending"
            : "descending";
      });
    } else if ((this.$parent as any).searchKey.default_order) {
      Object.keys((this.$parent as any).searchKey.default_order).forEach(
        (item: any) => {
          this.sort_default.prop = item;
          this.sort_default.order =
            (this.$parent as any).searchKey.default_order[item] == 4
              ? "ascending"
              : "descending";
        }
      );
    }
    if (this.isDefault) {
      //重新拉取
      this.columnsList = new Array();
      this.columnsList = this.columnsList.concat(this.$slots.default);
    }
    //判定是否有缓存,有则提前设置列
    this.columnCache.forEach((item: any, index: number) => {
      if (item.name === location.hash) {
        this.checkList = new Array();
        item.value.split(",").forEach((val: string) => {
          if (val) {
            this.checkList.push(parseInt(val));
          }
        });
        this.setTable(item.value);
        return false;
      }
    });
  }
  //设置列
  setTable(checkids = "") {
    if (!checkids && this.checkList.length == 0) {
      //设置默认
      this.isDefault = true;
      //记录缓存
      this.addCache("");
      //隐藏筛选器
      this.cellDialog = false;
      //重新渲染表格
      this.isTable = false;
      setTimeout(() => {
        this.isTable = true;
      }, 10);
      return;
    }
    //转义字符串,用于判定方便
    let _checkids = checkids ? checkids : "," + this.checkList.join(",") + ",";
    //重新实例化
    this._default = new Array();
    //循环判定
    this.columnsList.forEach((item: any, index: number) => {
      if (_checkids.indexOf("," + index + ",") > -1) {
        delete item.componentOptions.propsData.width;
        //添加
        this._default.push(item);
      }
    });
    //设置不默认
    this.isDefault = false;
    //设置列
    this.$slots.diy = this._default;
    //重新渲染表格
    this.isTable = false;
    setTimeout(() => {
      this.isTable = true;
    }, 1);
    if (!checkids) {
      //记录缓存
      this.addCache(_checkids);
      //隐藏筛选器
      this.cellDialog = false;
    }
  }
}
</script>

<style lang="scss">
.column_label {
  width: 175px;
}
.setting{
    font-size: 24px;
    cursor: pointer;
    float: right;
    margin-top: -27px;
}
</style>