给el-table实现列显隐

12 篇文章 2 订阅
3 篇文章 0 订阅

在ElTable基础上添加列隐藏,在使用el-table 时候,想要实现这种效果一般是给每个el-form-item添加v-if 判断的,看看el-table中看有没有什么办法能使用更方便的方式去管理,最后发现内部的【插入】和【删除】两个方法可以达到我们要的效果。

具体效果如下

在这里插入图片描述

  1. 业务组件定义好数据,支持默认隐藏
  2. 使用right-toolbar 切换显示&隐藏 将切换的值保存在 vuex + vuex-persistedstate 方便刷新页面保持动作
  3. 对 el-table 源码进行改动
改动文件目录
  • el-table
    • table.vue
    • store
      • index.js

覆盖注册组件

import ElementUI from "element-ui"
import "element-ui/lib/theme-chalk/index.css";
Vue.use(ElementUI);
import ElTable from '@/components/element-ui/ElTable';
import ElTableColumn from "@/components/element-ui/el-table-column";
Vue.component(ElTable.name, ElTable); // 这个步骤同等于对象重新赋值的操作
Vue.component(ElTableColumn.name, ElTableColumn);
项目使用方式
将 table 传递给 right-toolbar
<template>
  <div>
    <right-toolbar :search="false" :table.sync="table" @interaction="(x) => (hiddenColumns = x)" :componentName="$options.name" />

    <el-table ref="table" :data="table.data" v-loading="table.loading" :hiddenColumns="hiddenColumns">
      <el-table-column align="center" type="selection" width="55" />
      <el-table-column align="center" label="类型" prop="type" />
      <el-table-column align="center" label="名称" prop="name" />
      <el-table-column align="center" label="描述信息" prop="desp" />
      <el-table-column align="center" label="值" prop="value" />
      <el-table-column align="center" label="默认值" prop="defaultValue" />
      <el-table-column align="center" label="操作" class-name="small-padding fixed-width">
        <template>
          <el-button size="mini" type="text" icon="el-icon-edit" >修改</el-button>
          <el-button size="mini" type="text" icon="el-icon-delete">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
export default {
  data() {
    return {
      table: {
        loading: false,
        table: [
          {
            type: "FilePath",
            name: "probeEnforcement",
            desp: "文件生成路径",
            value: "/home/qchen/",
            defaultValue: "3",
          },
        ],
      },
      hiddenColumns: [], // 默认隐藏的列
      checkTableInfo: ["类型", "名称", "描述信息", "值", "默认值", "操作"],
    };
  },
};
</script>
自定义组件(right-toolbar)
<template>
  <div class="top-right-btn" :style="style">
    <el-row>
      <el-tooltip effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top" v-if="search">
        <el-button size="mini" circle icon="el-icon-search" @click="$emit('update:showSearch', !showSearch)" />
      </el-tooltip>

      <el-tooltip effect="dark" content="刷新" placement="top">
        <el-button size="mini" circle icon="el-icon-refresh" @click="$emit('queryTable')" />
      </el-tooltip>

      <el-tooltip v-if="checkTableInfo.length" effect="dark" content="显隐列" placement="bottom-start">
        <el-popover v-model="visible" placement="right" trigger="click">
          <p class="clearfix">
            <i class="el-icon-refresh fr" @click="reset" />
          </p>

          <el-checkbox-group v-model="checks">
            <el-checkbox style="display: block" v-for="item in checkTableInfo" :disabled="['selection', '操作'].includes(item)" :key="item" :label="item" />
          </el-checkbox-group>

          <el-divider class="my-10" />

          <template>
            <el-button size="mini" type="primary" @click="submit(), (visible = false)">确定</el-button>
            <el-button v-if="componentName" size="mini" @click="cancel">取消</el-button>
          </template>

          <el-button class="ml-10" slot="reference" size="mini" circle icon="el-icon-menu" />
        </el-popover>
      </el-tooltip>
    </el-row>
  </div>
</template>

<script>
import { mapState, mapMutations } from 'vuex';
import { localstorageGet, localstorageSet } from '@/lib/util';

export default {
  name: 'RightToolbar',
  data() {
    return {
      checks: Array.from(this.table.checkTableInfo.filter(item => !this.table.hiddenColumns.includes(item)) || []),
      checkTableInfo: Array.from(this.table.checkTableInfo || []),
      visible: false,
    };
  },
  props: {
    showSearch: { type: Boolean, default: true },
    search: { type: Boolean, default: true },
    gutter: { type: Number, default: 10 },
    table: { type: Object, default: () => ({}) },
    componentName: { type: String, default: '' },
  },
  mounted() {
    const cacheColumn = this.tableColumns[this.componentName];

    if (cacheColumn) {
      this.checks = this.table.checkTableInfo.filter(item => !cacheColumn.includes(item));
      this.$emit('interaction', cacheColumn);
    } else {
      const arr = this.table.checkTableInfo.filter(item => !this.checks.includes(item));
      this.$emit('interaction', arr);
    }
  },
  methods: {
    // 项目中会使用vuex ,vuex 中有持久化存储到localstorage的数据
    ...mapMutations('tablecolumn', ['setTableCache']),
    submit() {
      const differs = this.table.checkTableInfo.filter(item => !this.checks.includes(item));
      this.$emit('interaction', differs);
      if (!this.componentName) return;
      this.setTableCache({ key: [this.componentName], value: differs });
    },
    cancel() {
      this.tableColumns[this.componentName]?.length && (this.checks = this.tableColumns[this.componentName]);
      this.visible = false;
    },
    reset() {
      this.checks = this.table.checkTableInfo;
      this.submit();
    },
  },
  computed: {
    ...mapState('tablecolumn', ['tableColumns']),
    style() {
      const ret = {};
      if (this.gutter) {
        ret.marginRight = `${this.gutter / 2}px`;
      }
      return ret;
    },
  },
};
</script>

<style lang="scss" scoped>
.top-right-btn {
  margin: 2px 12px;
}
</style>

table组件中 (./el-table/table.vue)
<script>
import { cloneDeep } from 'lodash-es'
...其他导入
export default {
  name: "ElTable",
  props: {
    hiddenColumns: {
      type: Array,
      default: () => [],
    },
    // ... 其他props
  },
  watch: {
    hiddenColumns: {
      immediate: true,
      handler(value) {
        ...其他代码
        const { states } = this.store;
        const { _columns } = states;

        if (!this.cache_columns || !this.cache_columns.length) {
          this.cache_columns = deepClone(_columns);
        }

        const show = this.cache_columns.filter(x => {
          if (['selection', 'index', 'expand'].includes(x.type)) return false;
          if (['#', '操作'].includes(x.label)) return false;
          return !value.includes(x.label);
        });

        const showLabels = _columns.map(x => x.label);

        show.forEach(item => {
          if (showLabels.includes(item.label)) return;
          this.store.commit('insertColumn', item, item.insertColumnIndex);
        });

        const hide = this.cache_columns.filter(x => {
          if (['selection', 'index', 'expand'].includes(x.type)) return false;
          if (['#', '操作'].includes(x.label)) return false;
          return value.includes(x.label);
        });

        hide.forEach(item => {
          const column = _columns.find(x => x.label === item.label);
          if (!column) return;
          this.store.commit('removeColumn', column);
        });
      },
    },
  }
};
</script>
store/index.js (./el-table/store/index.js)
Watcher.prototype.mutations = {
  ...其他代码
  insertColumn(states, column, index, parent) {
    let array = states._columns;
    if (parent) {
      array = parent.children;
      if (!array) array = parent.children = [];
    }

    if (typeof index !== 'undefined') {
      array.splice(index, 0, column);
    } else {
      array.push(column);
    }

    if (column.type === 'selection') {
      states.selectable = column.selectable;
      states.reserveSelection = column.reserveSelection;
    }
    
    /**
     * 加入 index 标识,插入时用到
     */
    if (!column.insertColumnIndex) {
      column.insertColumnIndex = index;
    }

    if (this.table.$ready) {
      this.updateColumns(); // hack for dynamics insert column
      this.scheduleLayout();
    }
  },
};

Watcher.prototype.commit = function (name, ...args) {...
};

Watcher.prototype.updateTableScrollY = function () {...
};

export default Watcher;

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值