当前位置: 首页 > 知识库问答 >
问题:

前端表格自适应列宽算法不能使表格扩充到容器大小该怎么办?

云项禹
2024-08-01

前端表格自适应列宽算法不能使表格扩充到容器大小该怎么办?

我希望可以根据表头字段长度和数据的长度来计算出每一列的宽度,但是计算出来的宽度使得表格的整体宽度小于容器的大小(当计算出来的宽度大于容器大小的时候,此时出现一个滚动条,显示是合适的,没有问题的),这该怎么办?

数据:
fields

const fields = [
    {
        "label": "序号",
        "prop": "xh",
    },
    {
        "label": "姓名",
        "prop": "xm",
    },
    {
        "prop": "xx",
        "label": "管理考核",
        "children": [
            {
                "prop": "jl",
                "label": "奖",
            },
            {
                "prop": "kf",
                "label": "罚",
            },
            {
                "prop": "hj",
                "label": "合计",
            }
        ],
    },
    {
        "prop": "ydjj",
        "label": "应得奖金",
    },
    {
        "prop": "sdjj",
        "label": "实得奖金",
    }
]

tableData

const tableData = [
 {
    "xh": 1,
    "xm": "屈敏",
    "jl": "11",
    "kf": "12",
    "hj": "6",
    "ydjj": "",
    "sdjj": ""
}]

实现思路:

export function calColsWidth(fields, tableData) {
    const fontSz = 12;
    const benchmarkRate = (fontSz && fontSz / 12) || 1
      // 空字符长度
    const nullstr = 10 * benchmarkRate + 2
      // 单个中文字符长度
    const chinese = 2 * benchmarkRate
      // 单个非中文字符长度
    const nChinese = benchmarkRate

    function width(val) {
        if (!val) {
            return  nullstr * 10
        } else {
            const strArr = val.toString().split("")
            const pattern = new RegExp("[\u4E00-\u9FA5]+")
            let re = strArr.map((str) => {
              // 是否为中文
            if (pattern.test(str)) {
               return chinese
            } else {
               return nChinese
              }
            })
            re = re.reduce((total, r) => total + r, 0)
            return (re + 2) * 10
        }
    }
    // 根据表头计算宽度
    function calColsWidthByHeader(fds) {
        let tot = 0;
        for(const e of fds) {
            const w = width(e.label);
            if(!e.children) {
                e.width = w;
            }else {
                const tw = calColsWidthByHeader(e.children);
                e.width = Math.max(w, tw);
            }
            tot += e.width;
        }
        return tot;
    }
    function findNode(prop, fds) {
        let res = null;
        for(const e of fds) {
            if(e.prop === prop) {
                res = e;
                break;
            }else if(e.children) {
                res = findNode(prop, e.children)
                if(res) break;
            }
        }
        return res;
    }
    // 根据表格数据设置宽度
    function calColsWidthByTableData() {    
        const mp = new Map()
        for(const row of tableData) {
            for(const e in row) {
                if(row.hasOwnProperty(e)) {
                    let fd = null;
                    if(mp.has(e)) {
                        fd = mp.get(e);
                    } else  {
                        fd = findNode(e, fields);
                        mp.set(e, fd);
                    }
                    if(fd) {
                        const w = width(row[e])
                        console.log(row[e], width(row[e]))
                        fd.width = Math.max(fd.width, w)
                    }
                }
            } 
        }
        // 叶子节点上的宽度更新了,但是非叶子节点上的宽度没有更新
        function update(fds) {
            let tot = 0;
            for(const e of fds) {
                if(e.children) {
                    e.width = update(e.children)
                }
                tot += e.width
            }
            return tot;
        }
        update(fields)
    }
    // 根据表头设置宽度
    calColsWidthByHeader(fields) 
    console.log("calColsWidthByHeader: ", JSON.parse(JSON.stringify(fields)));
    // 根据表格数据设置宽度
    calColsWidthByTableData()
    console.log("calColsWidthByTableData: ", JSON.parse(JSON.stringify(fields)));
    return fields;
}

计算得到的新fileds,每个字段增加了新的width属性

[
    {
        "label": "序号",
        "prop": "xh",
        "width": 60
    },
    {
        "label": "姓名",
        "prop": "xm",
        "width": 60
    },
    {
        "prop": "xx",
        "label": "管理考核",
        "children": [
            {
                "prop": "jl",
                "label": "奖",
                "width": 40
            },
            {
                "prop": "kf",
                "label": "罚",
                "width": 40
            },
            {
                "prop": "hj",
                "label": "合计",
                "width": 60
            }
        ],
        "width": 140
    },
    {
        "prop": "ydjj",
        "label": "应得奖金",
        "width": 120
    },
    {
        "prop": "sdjj",
        "label": "实得奖金",
        "width": 120
    }
]

除了不能占据整个容器之外,这里的width的计算可能也需要改进一下,因为表格数据中的数字11被换行了。
image.png

 const fontSz = 12;
    const benchmarkRate = (fontSz && fontSz / 12) || 1
      // 空字符长度
    const nullstr = 10 * benchmarkRate + 2
      // 单个中文字符长度
    const chinese = 2 * benchmarkRate
      // 单个非中文字符长度
    const nChinese = benchmarkRate

    function width(val) {
        if (!val) {
            return  nullstr * 10
        } else {
            const strArr = val.toString().split("")
            const pattern = new RegExp("[\u4E00-\u9FA5]+")
            let re = strArr.map((str) => {
              // 是否为中文
            if (pattern.test(str)) {
               return chinese
            } else {
               return nChinese
              }
            })
            re = re.reduce((total, r) => total + r, 0)
            return (re + 2) * 10
        }
    }

共有1个答案

娄阳舒
2024-08-01

针对你的问题,即前端表格自适应列宽算法不能使表格完全扩展到容器大小,同时确保表格内容不被截断或换行,你可以考虑以下解决方案:

1. 改进宽度计算算法

首先,你的宽度计算算法假设了每个字符(包括数字和中文)占用的像素宽度是固定的,这在实践中可能不准确,因为不同字体和不同浏览器对字符渲染的宽度可能会有所不同。因此,一个更精确的方法是根据实际渲染的文本计算宽度。

然而,如果你坚持使用这种基于字符的算法,你可以考虑添加一个“填充宽度”来确保表格总宽度能够扩展到容器宽度。

2. 填充宽度

在计算出所有列的宽度总和后,你可以计算容器宽度与列宽总和之间的差值,并将这个差值平均分配到每列上(或者根据列的优先级、内容长度等条件进行更复杂的分配)。

function distributeExtraWidth(fields, containerWidth, totalWidth) {
    const extraWidth = containerWidth - totalWidth;
    if (extraWidth > 0) {
        // 分配额外的宽度
        const columnsCount = fields.reduce((count, field) => count + (field.children ? field.children.length : 1), 0);
        const perColumnWidth = extraWidth / columnsCount;

        function updateFieldWidth(fields) {
            for (const field of fields) {
                if (field.width) {
                    field.width += perColumnWidth;
                }
                if (field.children) {
                    updateFieldWidth(field.children);
                }
            }
        }

        updateFieldWidth(fields);
    }
}

// 在你的函数中调用它
// ...
const totalWidth = calColsWidthByHeader(fields);
const containerWidth = document.getElementById('your-table-container').offsetWidth; // 假设你的容器有一个ID
distributeExtraWidth(fields, containerWidth, totalWidth);
// ...

3. 使用CSS Flexbox或Grid

另一个解决方案是避免在JavaScript中计算宽度,而是使用CSS的Flexbox或Grid布局来自动处理列宽。你可以设置表格的容器为Flexbox或Grid容器,并设置表格列(或单元格)为Flex项目或Grid项,然后利用CSS的flex-growgrid-template-columns: repeat(auto-fill, minmax(minWidth, 1fr))等属性来实现自动宽度分配。

4. 考虑内容换行

如果表格的某些列包含非常长的文本,并且你希望保持列宽不变以避免表格过宽,你可能需要允许内容换行。这可以通过CSS的white-space: normal;word-wrap: break-word;属性来实现。

5. 测试和调试

最后,不要忘记在不同的浏览器和设备上测试你的表格,以确保它们都能正确显示。使用浏览器的开发者工具来检查元素的样式和布局,可以帮助你找到可能的问题并进行调试。

 类似资料:
  • 本文向大家介绍EasyUI 数据表格datagrid列自适应内容宽度的实现,包括了EasyUI 数据表格datagrid列自适应内容宽度的实现的使用技巧和注意事项,需要的朋友参考一下 项目初期在加载数据表格的时候为了提高表格数据渲染速度,设置了默认宽度。 现需求需要加一个表格自适应的功能,触发改功能,改变列宽度,但是不重新渲染表格,不发生数据请求。 设计思路,遍历每项的所有数据,比较字节符串长度,

  • 本文向大家介绍layui表格 列自动适应大小失效的解决方法,包括了layui表格 列自动适应大小失效的解决方法的使用技巧和注意事项,需要的朋友参考一下 如下所示: 从官网复制的表格,修改成自适应宽度后失效,原因如下: 以上这篇layui表格 列自动适应大小失效的解决方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。

  • 本文向大家介绍使用Element UI表格如何设置列宽的宽度自适应?相关面试题,主要包含被问及使用Element UI表格如何设置列宽的宽度自适应?时的应答技巧和注意事项,需要的朋友参考一下 https://kuaizi-co.github.io/kz-table/ 列宽自适应

  • 问题内容: 有没有一种使用HTML / CSS(具有相对大小)的方法来使一行单元格拉伸包含它的表的整个宽度? 单元格的宽度应相等,并且外部表格的大小也应使用来动态变化。 目前,如果我没有指定固定大小,单元格会自动调整大小以适合其内容。 问题答案: 您甚至不必为单元格设置特定的宽度,足以均匀地分布单元格。 请注意,要使用表格样式的元素,必须设置宽度(在我的示例中为100%)。

  • 在使用VTable表格库做报表数据展示时,如果列的总数不足以撑开整个容器的宽度,我想能自动拉宽来适应容器大小,但当列的数量较多总宽度大于容器宽度时,又可以正常出滚动条来横向滚动。这个效果怎么实现呢?

  • 试了很多方法,只能自适应浏览器大小,不能自适应盒子大小,想问下各位大佬有什么方法可以实现我想要的效果?