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) => { // 生成列的key d.columnKey = d.props ? d.props.label : window.btoa(index.toString()); // 生成列的prop if (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> <TableControl style="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>
效果圖