公共Hooks封装之自定义表格数据列渲染useTableColumns

我正在参加「掘金·启航计划」

写在前面
对于经常需要开发企业管理后台的前端开发来说,必不可少的需要使用表格对于数据进行操作,在对于现有项目进行代码优化时,封装一些公共的Hooks.
本篇文章为useTableColumns.js

基于个人项目环境进行封装的Hooks,仅以本文介绍封装Hooks思想心得,故相关代码可能不适用他人

项目环境

Vue3.x + Ant Design Vue3.x + Vite3.x

封装思考:何为自定义表格数据列渲染,其为何种场景服务

根据实际业务场景而来,为避免法律风险,部分截图内容脱敏处理

如下图,当表格内容的列非常多时,正常情况下,我们通常采取的方式是左右两侧的列,即左侧Key列和右侧操作列固定,中间列内容区域滚动。而当数据列内容非常多并且每列数据都具备其真实意义时,我们该考虑采取更好的方式,对于不同的系统使用人员,通常每个人的关注点都是不一样的,因此,可以做成每个人主动去改变表格列项展示为其关注的数据列。

tableColumnsDemo.png
结合上述场景,以及优化考虑,便得到如下的个人解决方案,useTableColumns的封装

封装分解:主要思路Columns

结合实际使用的UI框架Ant Design Vue,Column 列描述数据对象,是 Columns 中的一项,Column 使用相同的 API.
常见的数据结构如下:

columns: [  
    {  
        title: '姓名',  
        dataIndex: 'name',  
        key: 'name',  
    },  
    {  
        title: '年龄',  
        dataIndex: 'age',  
        key: 'age',  
    },  
    {  
        title: '住址',  
        dataIndex: 'address',  
        key: 'address',  
    },  
],  

上面的数据结构中,指出了表格内每一列数据对应的表头、数据索引等相关信息,此外,还有官方文档中提供的一系列API。结合上面已经提供的截图,思路其实很明显了,动态去变更这个JSON数据而已。实际使用中,将需要参与变更的数据列,添加自定义属性:addFilter.

封装分解:下拉菜单-筛选展示数据列组件

<template #headerCell="{ column }">  
    <template v-if="column.key === 'action'">  
        <div class="flex justify-between items-center">  
            <span>操作</span>  
            <table-field-filter :columns="columns" @change="onFilterColumnChange" />  
        </div>  
    </template>  
</template>  

以上代码基于实际项目UI FrameWork — Ant Design Vue,类似的也可以看下其他框架,如ElementUITable组件提供的相关API或写法.

项目内,我选择了将onFilterColumnChange放置在了表格操作列的表头上,实际使用过程中,也可以放置在其他区域,例如筛选模块、标题等,具体还是看怎么设计,不破坏现有的布局或需要UI设计师稍微设计一下~

封装分解:Columns动态变更

let includeColumns = []; // 参与过滤的列表字段集合  
  
let excludeColumns = []; // 不参与过滤的列表字段集合  
  

const columns = shallowRef([]); // 需要展示的列表字段集合  
  
if (options?.initFilterKeys.length > 0) {  
    for (let i = 0, len = options.initFilterKeys.length; i < len; i++) {  
        const key = options.initFilterKeys[i];  
        const index = $columns.findIndex(item => item.key === key);  
        $columns.splice(index, 1);  
    }  
}  
  

目前实现方式是将参与筛选的表格列放到一个数组内,再将不参与过滤的项放到另一个数组内,再将其合并。结合实际业务中,对于某些特殊场景可能没有对应数据,不参与显示控制,例如企业后台-企业微信/或其他类似生态账号登录的体系中,实际对于账号控制是不需要的(或因政策限制等其他原因,考虑屏蔽表格内账号显示),当然这个是结合实际业务来的,在此不做赘述~

封装分解:utils–getArrayDiff

/**  
* @description 筛选两个数组不同的元素  
*/  
export function getArrayDiff(arr1, arr2) {  
    return arr1.concat(arr2).filter((item, index, arr) => arr.indexOf(item) === arr.lastIndexOf(item));  
}  

useTableColumns.js完整代码

import { shallowRef } from 'vue';  
import { cloneDeep } from 'lodash-es';  
import { getArrayDiff } from '@/utils/util';  
  

export function useTableColumns(defaultColumns, options) {  
    if (!defaultColumns || !Array.isArray(defaultColumns)) return;  

    let includeColumns = []; // 参与过滤的列表字段集合  

    let excludeColumns = []; // 不参与过滤的列表字段集合  

    const columns = shallowRef([]); // 需要展示的列表字段集合  

    const onFilterColumnChange = keys => {  
        const orKeys = includeColumns.map(item => item.key);  
        const delKeys = getArrayDiff(orKeys, keys);  
        const $columns = cloneDeep(includeColumns);  
        for (let i = 0, len = delKeys.length; i < len; i++) {  
            const key = delKeys[i];  
            const index = $columns.findIndex(item => item.key === key);  
            $columns.splice(index, 1);  
        }  
        columns.value = [...$columns, ...excludeColumns];  
    };  

    // 初始化字段处理  
    const initColumns = () => {  
        const $columns = cloneDeep(defaultColumns);  
        if (options?.initFilterKeys.length > 0) {  
            for (let i = 0, len = options.initFilterKeys.length; i < len; i++) {  
                const key = options.initFilterKeys[i];  
                const index = $columns.findIndex(item => item.key === key);  
                $columns.splice(index, 1);  
            }  
        }  
        for (let i = 0, len = $columns.length; i < len; i++) {  
            const item = $columns[i];  
            if (item.addFilter) {  
                includeColumns.push(item);  
            } else {  
                excludeColumns.push(item);  
            }  
        }  
        columns.value = $columns;  
    };  

    initColumns();  

    return {  
        columns,  
        onFilterColumnChange,  
    };  
}  

后续思考:当前的封装是否有问题呢?如何优化呢?

Hooks中对于Columns的处理是使用2个数组来分别暂存需要筛选和不需要筛选的表格列,由于实际项目中暂时只有一个页面「文中截图所示」需要处理上述操作,而对于表格列数据,目前除了操作列,其他的都添加了addFilter自定义属性,而在实际业务需求中,可能表格字段会出现以下情况:

仅简要说明

[字段A, 字段B, 字段C, 字段D, 字段E, 字段F, 字段G, 操作列 ]  

如果除操作列都加上addFilter自定义属性,则是和我目前使用的方式无异,也不存在问题,

如果以上字段中,作为标识(字段A、字段C、字段G)不参与筛选,其余的字段参与筛选,目前封装的Hooks是不满足需求的,因为按照现有的写法会导致colums数组经过onFilterChange之后,会变成

[字段A, 字段C, 字段G, 字段B, 字段E, 字段F, 操作列 ]  

这种情况,对于原表格来说,原有的索引顺序被打破,仅满足了筛选,但不是原位置”删除/隐藏”的筛选,对于实际业务来说,可能不满足~
该如何解决呢?目前由于需求迭代,暂时没时间处理~待后续进行优化~

当然也更期待读者盆友们提供解决思路,或一起优化下代码吧~

写在最后

  • 文章内容为个人基于实际项目并脱敏处理的原创内容,如需要转载请备注原文链接~
  • 如果看完文章对于你有帮助,就来一键三连吧~更欢迎您在评论区进行指点

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYWFhrf7' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片