vue3 el-table控制列顯示隱藏

居无常發表於2024-11-23

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>

  效果圖

相關文章