碎碎念:有点难用,不丝滑(以下介绍的难点不是真的难,只是有点点点难用)
背景:需要实现表格的行列合并以及图标的嵌入,想到使用组件库组件来方便开发
链接:TDesign Web Vue Next
难点1:数据的定义
看到官方的代码实现,定义结构感觉有点乱
官方示例图:
官方代码:
这部分主要就是定义table结构,
data:表格数据;columns:表头结构
rowkey要定义,不然错误信息
rowspan-and-colspan:定义表格行列合并的规则(合并的框会框会覆盖后面的)
<template><div><t-table:bordered="true":data="data":columns="columns"row-key="i":rowspan-and-colspan="rowspanAndColspan"resizabletable-layout="fixed"lazy-load/></div>
</template>
然后是js里的
statusNameListMap定义的是type有关样式值,存关键的对象
data用new Array生成
colums里定义表头的结构,colspan定义的是列合并
rowspanAndColspan = ({ col,row, ,colIndex , rowIndex })
其中 col 是表头信息, row是一行的信息 ,colIndex是单元格列 index, rowIndex是单元格行 index
<script setup lang="jsx">
import { ErrorCircleFilledIcon, CheckCircleFilledIcon, CloseCircleFilledIcon } from 'tdesign-icons-vue-next';const statusNameListMap = {0: { label: '审批通过', theme: 'success', icon: <CheckCircleFilledIcon /> },1: { label: '审批失败', theme: 'danger', icon: <CloseCircleFilledIcon /> },2: { label: '审批过期', theme: 'warning', icon: <ErrorCircleFilledIcon /> },
};const data = new Array(6).fill(null).map((_, i) => ({i,status: i % 3,applicant: ['贾明', '张三', '王芳'][i % 3],channel: ['电子签署', '纸质签署', '纸质签署'][i % 3],type: ['审批通过', '已过期', '审批失败', '审批中'][i % 4],detail: {email: ['w.cezkdudy@lhll.au','r.nmgw@peurezgn.sl','p.cumx@rampblpa.ru','b.nmgw@peurezgn.sl','d.cumx@rampblpa.ru',][i % 5],},needed: ['Y', 'N'][i % 1],description: ['宣传物料制作费用', 'algolia 服务报销', '相关周边制作费', '激励奖品快递费'][i % 4],createTime: '2021-11-01',
}));const columns = [{ colKey: 'applicant', title: '申请人', width: '100' },{colKey: 'status',title: '申请状态',width: '150',cell: (h, { row }) => {return (<t-tag shape="round" theme={statusNameListMap[row.status].theme} variant="light-outline">{statusNameListMap[row.status].icon}{statusNameListMap[row.status].label}</t-tag>);},},{colKey: 'description',title: '审批事项',width: 150,},{colKey: 'detail.email',title: '邮箱地址',},{colKey: 'channel',// 多行表头合并请参考「多级表头示例」title: '其他信息',// 仅适用于单行表头合并列colspan: 2,// 设置列样式,注释的示例代码有效// attrs: ({ type, col, row, colIndex, rowIndex }) => ({// style: {// color: 'blue',// },// }),},{colKey: 'createTime',title: '创建时间',},
];const rowspanAndColspan = ({ col, rowIndex, colIndex }) => {if (colIndex === 0 && rowIndex % 2 === 0) {return {rowspan: 2,};}if (col.colKey === 'description' && rowIndex === 1) {return {colspan: 2,rowspan: 2,};}if (col.colKey === 'email' && rowIndex === 4) {return {colspan: 2,rowspan: 2,};}
};
</script>
打印了下data的结构:发现每个字段都有,是个数组对象,所以合并的时候数据是会占位,并被前面的覆盖掉
难点二:样式修改
官方的样式只提供了表格的样式修改
1. 行的类名rowClassName设置
2. 列的类名className设置
3. attr: { style: { } }设置该列的内联样式
4. cell:表格的渲染函数,可自定义插槽作为该列,比如增加图标
5. title:表头的渲染函数,可自定义插槽作为表头,比如增加图标
6. render:可以渲染表头,也可以渲染单元格,相当于cell或title
官方代码:我这里只放部分对应的
// 第一种 (王芳那一行)
<t-table row-key="id" :data="data" :columns="columns" :row-class-name="getRowClassName"><template #footerSummary><div class="t-table__row-filter-inner"><InfoCircleIcon />近期申请耗时较长</div></template>
</t-table>const getRowClassName = ({ rowIndex }) => {if (rowIndex === 2) return 'custom-third-class-name';return '';
};.t-demo__style .t-table .custom-third-class-name > td {background-color: var(--td-brand-color-light);font-weight: bold;
}// 第二种(第四列)
{colKey: 'channel',title: '签署方式',width: 120,align: 'right',className: () => {return 'custom-cell-class-name';},},.t-table td.custom-cell-class-name {color: orange;font-weight: bold;
}// 第三种 (第三列){colKey: 'time',title: '申请耗时(天)',width: 120,align: 'center',// 设置单元格类名className: ({ row }) => {if (row.time >= 9) {return 'custom-cell-class-name';}return '';},attrs: ({ row }) => {if (row.time >= 9) {return {style: {fontWeight: 600,backgroundColor: 'var(--td-warning-color-light)',},};}},},
<t-table :data="data" :columns="columns" row-key="property" lazy-load><!-- 自定义表头,title值为插槽名称 --><template #title-slot-name><div style="display: flex; align-items: center"><UserCircleIcon style="margin-right: 8px" />申请人</div></template>
</t-table>// cell colums里的 对应审批状态的单元格
{title: '审批状态',colKey: 'status',// 使用 cell 方法自定义单元格:cell: (h, { row }) => {return (<t-tag shape="round" theme={statusNameListMap[row.status].theme} variant="light-outline">{statusNameListMap[row.status].icon}{statusNameListMap[row.status].label}</t-tag>);},},// title 对应有图标的表头
{colKey: 'applicant',title: 'title-slot-name',width: 120,},// render 对应申请时间
{colKey: 'createTime',// render 可以渲染表头,也可以渲染单元格。但 title 只能渲染表头,cell 只能渲染单元格render(h, context) {const { type, row, col } = context;return {title: '申请时间',cell: row && row[col.colKey],}[type];},},
然后以下是我的使用,我的实现结果,贴图:
表格结构定义:
colums: 表头 定义字段,宽度,行合并/列合并,表头对应该列的样式
table:定义表格数据,其中字段对应表头字段,然后可以设置行、列合并(非自带),传给下面函数处理
tableList:由于没设标识,所以给数据增加index作为标识,不然会报错
rowspanAndColspan:函数,设置单元格所占的行,列的格子数,会对满足条件的单元格使用
attrs设置了样式,cell,title绑定了插槽
// 表头 定义字段,宽度,行合并/列合并,表头对应该列的样式
const columns = [{colKey: 'compare',title: '测试1',width: '200px',colspan: 2,attrs: () => {return {style: {fontWeight: 600,},}},},{colKey: 'content',title: '测试2',width: '279px',align: 'center',},{colKey: '测试3',title: 'title-vip',width: '239px',align: 'center',cell: 'vip',attrs: () => {return {style: {backgroundColor: 'rgba(239, 158, 0, 0.1)',border: '1px solid #FFD583',},}},},{colKey: 'normal',title: '测试4',width: '239px',align: 'center',cell: 'normal',},{colKey: 'other',title: '测试5',width: '239px',align: 'center',cell: 'other',},
]// 定义表格数据,其中字段对应表头字段,然后可以设置行、列合并,这里主要是传给下面函数处理
const table = [{compare: '项目',content: '项目',vip: true,normal: 'test',other: false,colspan: 2,}, {compare: '项目',vip: true,normal: 'test',other: '其他',colspan: 2,
}, {compare: '项目',content: '项目',vip: true,normal: true,other: false,rowspan: 4,
}, {compare: '项目',content: '项目',vip: true,normal: true,other: false,
}, {compare: '项目',content: '项目',vip: true,normal: true,other: false,
}, {compare: '项目',content: '企业',vip: true,normal: true,other: false,
}, {compare: '项目测试',content: '',vip: true,normal: true,other: '其他',colspan: 2,
}, {compare: '下载',content: '',vip: true,normal: '其他',other: '其他',colspan: 2,
}, {compare: '项目查看 ',content: '',vip: true,normal: '其他',other: '其他',colspan: 2,
}, {compare: '项目查看',content: '项目1',vip: true,normal: '其他',other: '其他',rowspan: 4,
}, {compare: '项目查看',content: '项目2',vip: true,normal: true,other: false,
}, {compare: '项目查看',content: '项目3',vip: true,normal: true,other: false,
}, {compare: '项目查看',content: '项目4',vip: '测试数据',normal: '其他',other: '其他',
}]// 给数据增加index作为标识,不然会报错
const tableList = table.map((item, index) => ({...item,index,
}))// 这个是设置单元格所占的行,列的格子数
function rowspanAndColspan({ row, colIndex }) {if (colIndex === 0) {const colspan = row.colspan || 1const rowspan = row.rowspan || 1return {colspan,rowspan,}}
}
表格:
<div><t-table:bordered="true":data="tableList":columns="columns"row-key="index":rowspan-and-colspan="rowspanAndColspan":resizable="false"lazy-load><template #title-vip><div class="cell-style font-600"><img src="../../assets/img/vip/icon-vip.png" alt="" class="vipimg cell-img mr-1"> 测试3</div></template><template #vip="{ row }"><div v-if="row.vip === true" class="cell-style"><div class="true cell-img"><img src="../../assets/img/vip/icon-true.png" alt=""></div></div><div v-else>{{ row.vip }}</div></template><template #normal="{ row }"><div v-if="row.normal === true" class="cell-style"><div class="true cell-img"><img src="../../assets/img/vip/icon-true.png" alt=""></div></div><div v-else>{{ row.normal }}</div></template><template #other="{ row }"><div v-if="row.other === false" class="cell-style"><div class="false cell-img"><img src="../../assets/img/vip/icon-false.png" alt=""></div></div><div v-else>{{ row.other }}</div></template></t-table>
</div>
踩坑1:
设置headerAffixedTop的吸顶,会因为表头合并而出现滚动条的问题,升级版本也没办法
解决方法:不能完全解决,只能采取相似效果实现
将表头的colspan:2的合并给去掉,然后把后边的第一个格子设置className,定义样式,左边框去掉
踩坑2:
表头的样式定义:无直接设置表头的样式
1. 使用className设置实现,但是需要设置每一个
2. 使用样式穿透
:deep(.t-table__th-cell-inner) {font-weight: 600;color: black;
}