封装el-table并实现前端动态显隐列及操作列宽度自适应

项目场景:

在管理系统中,前端多用表格展示数据,而有些时候数据列会比较多,对于某些用户来说,有些数据列不必关注,则需要可以根据自己想要看的数据来改变表头列显示哪些隐藏哪些

我elementPlus用得多,因此便想对el-table进行简单封装,实现前端动态显隐列及操作列宽度自适应

在写前也参考过很多人的代码,但是很多都要额外传递参数,或者将数据组建成特定格式,很不方便;因此我此次封装希望少进行一些额外配置,力图还原el-table的用法

写得不好的地方多多见谅…


实现效果:

提示:先上个效果图,要是不符合大家想要的效果,可以及时看下一篇:

GIF图:

在这里插入图片描述


代码:

提示:下面是具体代码:

(1)组件代码

<template>
    <el-table ref="tableRef" v-bind="$attrs" :key="Math.random()">
        <template v-for="(item) in slotList">
            <component
                v-if="item.props != null && initialColumnList.some((col) => { return item.props.label == col.label && col.isShow == true })"
                :is="item">
            </component>
        </template>
        <el-table-column align="center" label="操作" fixed="right" :width="operateColumnWidth">
            <template #header>
                <el-popover placement="bottom" popper-class="column-popover" :width="200" trigger="hover">
                    <template #reference>
                        <span>
                            操作
                            <el-icon>
                                <ArrowDownBold />
                            </el-icon>
                        </span>
                    </template>
                    <el-checkbox class="column-checkgroup-item" v-model="showAllColumnFlag"
                        :indeterminate="isIndeterminate" @change="handleCheckAllChange">全选</el-checkbox>
                    <el-divider />
                    <el-checkbox class="column-checkgroup-item" v-for="(item) in initialColumnList"
                        v-model="item.isShow" :label="item.label" :key="item.label" :disabled="item.label == '操作'" />
                </el-popover>
            </template>
            <template #default="scope">
                <div ref="operateItemGroup">
                    <slot name="operate" :scope="scope" />
                </div>
            </template>
        </el-table-column>
    </el-table>
</template>

<script setup lang="ts">
import { RendererElement } from 'vue'
import { ElTable } from 'element-plus';

const slots = useSlots()
const slotList = ref<RendererElement[]>([]) // 所有列,甚至包含注释
const initialColumnList = ref([]) // 正常列,排除注释内容
const showAllColumnFlag = ref(true);

const tableRef = ref<InstanceType<typeof ElTable>>()
const operateItemGroup = ref()

const emits = defineEmits(["getTableRef"]);

// 用于多选
const getTableRef = () => {
    emits('getTableRef', tableRef.value)
}

// 操作列宽度
const operateColumnWidth = ref(0)
// 动态设置操作列宽
watch(
    () => operateItemGroup.value,
    () => {
        if (operateItemGroup.value) {
            if(operateItemGroup.value.children.length==0){
                // 设置为0,el-table-column会自己设置一个默认宽度
                // 设置为1,目前会造成操作列基本不显示,即由于操作列处有可以选择哪些列不显示
                // 操作列不显示后,即没办法选择哪些列不显示
                operateColumnWidth.value = 1;
            }else{
                operateColumnWidth.value = operateItemGroup.value.children.length * 90;
            }
        }
    }
)

onMounted(() => {
    getTableRef();
    initSlotList();
})

// 初始化所有列
const initSlotList = () => {
    if (slots.default) { // el-table-column 使用时不传name 所以属于默认插槽
        slotList.value = slots.default() || [] // 语法
        initDynamicColumn() // 初始化动态列
    }
}

// 初始化动态列
const initDynamicColumn = () => {
    slotList.value.map(item => {
        const colProps = item.props
        // 存label,即表头名称,不存prop属性是因为,有些列使用插槽无需使用prop属性 
        if (colProps != null && typeof colProps === 'object' && colProps.label) {
            initialColumnList.value.push({ label: colProps.label, isShow: true })
        }
    })
    initialColumnList.value.push({ label: "操作", isShow: true })
}

// 列选中与半选的状态控制, 条件就是 当前选中的数据个数大于0 且 小于所有列的总数
const isIndeterminate = computed<boolean>(() => {
    const showColumnArray = initialColumnList.value.filter((item) => {
        return item.isShow == true
    });
    return showColumnArray.length > 0 && showColumnArray.length < initialColumnList.value.length
})

// 列全选与否的事件控制器
const handleCheckAllChange = (boolean: any) => {
    if (boolean) { // 全选 
        for (let i = 0; i < initialColumnList.value.length; i++) {
            initialColumnList.value[i].isShow = true;
        }
    } else { // 全不选
        for (let i = 0; i < initialColumnList.value.length; i++) {
            if (initialColumnList.value[i].label != "操作") {
                initialColumnList.value[i].isShow = false;
            }
        }
    }
}

</script>

<style scoped lang="scss">
</style>

(2)父组件使用参考

        <BPTable :data="firstTableData"  border stripe highlight-current-row>
            <el-table-column type="index" label="序号" align="center" width="50" />
            <el-table-column property="name" align="center" label="菜单名称" />
            <el-table-column prop="remark" align="center" label="权限备注" />
            <!-- 操作列 -->
            <template #operate="obj">
                <el-button v-perms="['sys:menu:update']" text icon="Edit" type="primary"
                    @click="openUpdateDialog(obj.scope.row)">
                    修改
                </el-button>
                <el-button v-perms="['sys:menu:delete']" text icon="Delete" type="danger"
                    @click="openDeleteDialog(obj.scope.row.id)">
                    删除
                </el-button>
            </template>
        </BPTable>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值