Ant Design Table自适应列宽,就是这么简单!
前言
目前在弄一个动态表格的项目,但由于没法知道每个列具体的内容,无法确定表格的列宽,而统一的设定会导致有的列内容很挤,有的列内容很空洞,整体视觉较差。
分析问题
Ant Design的Table组件,column在不设置width的时候,所有列会平分table的宽度,导致有的表头显示有问题,所以我们肯定需要指定每个列的列宽。现在问题是如何精确的算出后台返回字符串长度的像素值(px)
Q: 能不能根据后台返回字符数
来确定列宽?
A: 不能。首先我们没法知道后台返回的字符含有的类型,是纯中文还是含有英文,数字,特殊字符等。这会让我们计算不准确
解决问题
本文使用canvas画布来实现对字符串的测量。
前置知识
canvas [传送门]
创建一个canvas对象
document.createElement("canvas")
方法获取这个元素的context——图像稍后将在此被渲染 HTMLCanvasElement.getContext()
CanvasRenderingContext2D.measureText()
方法返回一个关于被测量文本TextMetrics
对象包含的信息(例如它的宽度TextMetrics.width
)。
**注意:** <canvas> 元素本身并没有绘制能力(它仅仅是图形的容器) - 您必须使用脚本来完成实际的绘图任务。 getContext() 方法可返回一个对象,该对象提供了用于在画布上绘图的方法和属性 复制代码
以下为测量文本实际长度的方法
// 默认字体为微软雅黑 Microsoft YaHei,字体大小为 14px function getTextWidth(text, font="14px Microsoft YaHei") { const canvas = document.createElement("canvas"); let context = canvas.getContext("2d"); context.font = font let textmetrics = context.measureText(text) return textmetrics.width; } 复制代码
自适应列宽表格
第一版
// 定义一个 Map 接收每列的长度值 let widthMap = new Map() // columns 为动态表格的表头数组 data为展示数据的数组 //作用是遍历所有数据拿到长度最长的一条记下他的宽度 data.forEach(target => { for(let key in target) { if(target.hasOwnProperty(key)) { let keyWidth = getTextWidth(target[key]) let curValue = widthMap.get(key) // 字段有值就放入数组 widthMap.set(key, Math.max(curValue,keyWidth)) } } }) //遍历表头,拿到对应表头的宽度与对应表头下内容比对,取最大值作为列宽,这样可以确保表头不换行。35为表头title左右的padding + border columns.map((item)=>{ // title,dataIndex为 ant design Table对应参数 let textWidth = getTextWidth(item.title) if(widthMap.get(item.dataIndex) < textWidth) { widthMap.set(item.dataIndex, textWidth) } return item.width = Math.ceil(widthMap.get(item.dataIndex)) + 35 }) 最后组件为 <Table columns={columns} dataSource={data} bordered rowKey={record => record.id} /> 复制代码
优点: 每列内容都能一目了然看全
缺点: 每一行由于后台返回内容长度不一样会导致有的行会比较空洞
适用范围: 内容长度比较均匀的列表。
第二版
// 定义一个 Map 接收每列的长度值 let widthMap = new Map() // columns 为动态表格的表头数组 data为展示数据的数组 //作用是遍历所有数据拿到长度,记下每一列的宽度 data.forEach(target => { for(let key in target) { if(target.hasOwnProperty(key)) { let keyWidth = getTextWidth(target[key]) // 字段有值就放入数组 widthMap.has(key) ? widthMap.set(key,widthMap.get(key).concat(keyWidth)) : widthMap.set(key,[].concat(keyWidth ? keyWidth : [] )) } } }) // 计算平均值,保证列宽尽量保持均衡 for(let [mapKey] of widthMap) { let valueArr = widthMap.get(mapKey) let len = valueArr.length let value = valueArr.reduce((acc, cur) => acc + (cur ? 1/cur : 1),0) widthMap.set(mapKey, len/value) } //遍历表头,拿到对应表头的宽度与对应表头下内容比对,取最大值作为列宽,这样可以确保表头不换行。35为表头title左右的padding + border columns.map((item)=>{ // title,dataIndex为 ant design Table对应参数 let textWidth = getTextWidth(item.title) if(widthMap.get(item.dataIndex) < textWidth) { widthMap.set(item.dataIndex, textWidth) } return item.width = Math.ceil(widthMap.get(item.dataIndex)) + 35 }) 最后组件为 <Table columns={columns} dataSource={data} bordered rowKey={record => record.id} /> 复制代码
优点: 每列列宽相对合理,且视觉上比较美观
总结
总的来说比较符合要求。若表格数据量较大时,此方法计算量也会相应增加,建议数据量大时,可以取前20行
数据作为标准计算列宽均值。
如有帮助,请点个❤ 谢谢!
完结撒花~~
作者:我要怎么学啊
链接:https://juejin.cn/post/7068937960296546334