场景:
表格可以根据需要切换某列展示/隐藏,结果可以存到本地也可以调用接口存到服务器

实现:
子组件:
<template><div class="table-column-control" @mouseenter="showAdd = true" @mouseleave="showAdd = false"><!-- 触发按钮 --><el-button type="text" class="control-btn" icon="Operation">{{ btnText || '显示' }}</el-button><!-- 复选框弹窗(鼠标悬浮显示) --><div v-show="showAdd" class="control-popup"><el-checkbox-group v-model="checkList"><el-checkboxv-for="item in tableHead":key="item.prop":label="item.label":value="item.prop":disabled="item.isDisabled"@change="(isChecked) => handleCheckChange(isChecked, item)"/></el-checkbox-group></div></div>
</template><script setup>
import { ref, watch, defineProps, defineEmits } from 'vue';// 1. 定义接收的 props(外部传入的配置和数据)
const props = defineProps({// 表格列配置(与原 tableHead 结构一致)tableHead: {type: Array,required: true,validator: (val) => {// 校验每一项必须包含 prop、label、isShow、isDisabledreturn val.every((item) => 'prop' in item && 'label' in item && 'isShow' in item && 'isDisabled' in item);}},// 初始选中的列(item.prop 数组,与原 checkList 一致)initChecked: {type: Array,default: () => []},// 按钮文本(支持自定义,默认“显示”)btnText: {type: String,default: '显示'},// 弹窗宽度(支持自定义,默认 300px)popupWidth: {type: String,default: '300px'}
});// 2. 定义对外触发的事件
const emit = defineEmits([// 列显示状态变更时触发:参数 (更新后的tableHead, 选中的prop数组)'columnChange'
]);// 3. 组件内部响应式状态
const showAdd = ref(false); // 控制弹窗显示/隐藏
const checkList = ref([...props.initChecked]); // 选中的列(item.prop 数组)// 4. 监听初始值变化(外部修改 initChecked 时同步)
watch(() => props.initChecked,(newVal) => {checkList.value = [...newVal];},{ deep: true, immediate: true }
);// 5. 处理复选框变更
function handleCheckChange(isChecked, item) {// 1. 更新当前列的 isShow 状态const updatedTableHead = props.tableHead.map((col) => (col.prop === item.prop ? { ...col, isShow: isChecked } : col));// 2. 同步 checkList(确保与 isShow 一致)if (isChecked) {!checkList.value.includes(item.prop) && checkList.value.push(item.prop);} else {checkList.value = checkList.value.filter((prop) => prop !== item.prop);}// 3. 对外触发事件,传递更新后的数据emit('columnChange', updatedTableHead, [...checkList.value]);
}
</script><style lang="less" scoped>
.table-column-control {display: inline-block;position: relative; /* 弹窗绝对定位的父容器 */// 触发按钮样式(保留原紫色).control-btn {padding: 0 4px;}// 弹窗样式(优化定位和交互).control-popup {position: absolute;top: 100%;right: 0;z-index: 1000; /* 确保弹窗在最上层 */padding: 12px;background: #fff;border: 1px solid #e5e7eb;border-radius: 6px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);box-sizing: border-box;.el-checkbox {margin-right: 16px;white-space: nowrap; /* 防止标签换行 */}}
}
</style>
父组件:
<children :tableHead="tableHead" :initChecked="checkList" @columnChange="changeHeaders" />// jsconst tableHead = ref([]); // 表头数据,注意与子组件的数据结构一致
const checkList = ref([]);/*** 表格表头切换* @param updatedTableHead 更新当前列的 isShow 状态* @param checkedProps*/
function changeHeaders(updatedTableHead, checkedProps) {tableHead.value = updatedTableHead;
}