TableControl.vue
<!-- 表格列显示隐藏控制*** 根节点为el-table,会穿透接收组件所有属性1、通过slots接收表格列,生成勾选项2、从缓存中读取数据,匹配勾选项;3、双向绑定,勾选项。表格列使用v-if判断显示隐藏; --> <template><el-table><template v-for="(item, index) in slotList" :key="index"><component v-if="onShowColumn(item)" :is="item" :column-key="item.columnKey"></component></template></el-table> </template><script setup lang="ts"> const slots = useSlots(); // 表格列 const fields = defineModel('fields', { type: Array, default: [] }); const slotList = ref<any[]>([]);/*** 初始化勾选列表*/ const initSlotList = () => {if (slots.default) {// el-table-column 使用时不传name 所以属于默认插槽const _slotList = slots.default() || [];_slotList.forEach((d: any, index: number) => {// 生成列的keyd.columnKey = d.props ? d.props.label : window.btoa(index.toString());// 生成列的propif (d.props) {d.props.prop = d.props.prop ? d.props.prop : d.props.label;}});fields.value = _slotList// 注释代码也会被当节点读取进来.filter((d: any) => d && d.props).map((d: any) => {return {label: d.props.label,propName: d.props.prop,checked: true,};});slotList.value = _slotList;} };function onShowColumn(col: any) {if (col && !col.props) {return true;}const field: any = fields.value.find((d: any) => d && d.propName === col.props.prop);return field && field.checked; }onMounted(() => {initSlotList(); // 关键, 初始化插槽 }); </script><style lang="scss" scoped> .column {&-all {border-bottom: 1px solid #dcdfe6;}&-list {max-height: 300px;overflow: auto;} } </style>
ColumnControl.vue
<!-- 表格列显示隐藏控制 --> <template><div class="table-toolbar"><el-button @click="showDialog = true" icon="Grid">表格列</el-button></div><el-dialog v-model="showDialog" title="表格列筛选" width="800"><div class="column-all"><el-checkbox v-model="checkedAll" :indeterminate="isIndeterminate" @change="onAllChange">全选</el-checkbox></div><div class="column-wrap"><div class="column-checkbox-group" v-if="fields.length > 0"><div class="column-checkbox" :class="{ active: item.checked }" v-for="(item, index) in fields" :key="index" @click="onItemClick(item)"><el-tooltip effect="dark" :content="item.label" placement="top" :show-after="300">{{ item.label }}</el-tooltip></div></div><div class="column-checkbox-group" v-else><el-empty description="暂无数据" /></div></div></el-dialog> </template><script setup lang="ts"> interface Field {label: string;propName: string;checked: boolean; } const emit = defineEmits(['update:modelValue', 'change']); // 定义父组件传过来的值 const props = defineProps({modelValue: {type: Array<Field>,default: () => [],}, });// 表格列 const fields = ref<Field[]>(props.modelValue); // 全选 const checkedAll = ref(true); // checkbox 的不确定状态 const isIndeterminate = ref(false); // 是否显示对话框 const showDialog = ref(false);/*** 全选*/ function onAllChange(val: boolean) {fields.value.forEach((item: any) => {item.checked = val;});isIndeterminate.value = false;emit('update:modelValue', fields.value); } function onItemClick(item: any) {item.checked = !item.checked;const checkedCount = fields.value.filter((d: any) => d.checked).length;checkedAll.value = checkedCount === fields.value.length;isIndeterminate.value = checkedCount > 0 && checkedCount < fields.value.length;emit('update:modelValue', fields.value); }// 监听路由的变化,设置网站标题 watch(() => props.modelValue,(newVal) => {fields.value = newVal || [];} ); </script><style lang="scss" scoped> .table-toolbar {padding-bottom: 8px;display: flex;justify-content: flex-end; } .column {&-wrap {border: 1px solid #d2d2d2;display: flex;min-height: 350px;}&-checkbox {width: 161px;padding: 10px;text-align: center;border-radius: 4px;border: 1px solid #9b9b9b;flex-shrink: 0;margin: 8px;float: left;cursor: pointer;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;box-sizing: border-box;&.active {background-image: url(/@/assets/images/sharedManage/plan/checkbox_selected.png);background-repeat: no-repeat;background-position: right top;border-color: #ff9302;color: #ff9302;}&-group {display: table;flex-wrap: wrap;padding: 4px 8px;}} } </style>
被改造页面
<template><div class="user-pages"><div class="user-pages-content"><ColumnControl v-model="fields"></ColumnControl><TableControlstyle="width: 100%"v-model:fields="fields"ref="tableRef"v-loading="state.loading":data="state.dataList":height="tableHeight":header-cell-style="tableStyle.headerCellStyle"show-summary:summary-method="getSummaries"><el-table-column prop="orderDate" label="月份" align="center" width="" /><el-table-column prop="companyName" label="所属公司" align="center" width="" /><el-table-column prop="regionName" label="大区" align="center" width="90" /><el-table-column prop="" label="区域" align="center" width="" /><el-table-column prop="province" label="省" align="center" width="" /><el-table-column prop="city" label="市" align="center" width="" /><el-table-column prop="area" label="区" align="center" width="" /></TableControl><pagination v-bind="state.pagination" @size-change="sizeChangeHandle" @current-change="currentChangeHandle" /></div></div> </template><script setup lang="ts"> // .... import ColumnControl from '/@/components/ColumnControl.vue'; import TableControl from '/@/components/TableControl.vue'; const fields = ref<any[]>([]); // .... </script><style scoped lang="scss"></style>
效果图