如何用HTML、CSS、原生JS实现可调整行列尺寸的100%宽度表格?
100%宽度可拖拽调整列宽/行高表格的最优实现方案
问题描述
需要创建宽度为100%的表格,支持拖拽调整列宽与行高。当前使用的原生JS代码在自适应内容宽度的表格上效果正常,但在100%宽度表格中存在问题:拖拽第二列向左时,第三列会被拉动调整,甚至出现列重叠情况。
现有代码的核心问题
现有实现只处理了向右拖拽时当前列与下一列的宽度分配,完全忽略了100%宽度表格的总宽度约束:向左拖拽缩小当前列时,未同步调整下一列宽度来维持表格总宽度,导致列宽总和失衡,最终出现重叠。
最优实现方案:修复原生JS适配100%宽度表格
以下是针对100%宽度表格优化后的完整实现,解决列重叠问题,同时保证交互流畅:
完整代码示例
JavaScript
const tables = document.getElementsByTagName("table"); for (let i = 0; i < tables.length; i++) { resizableGrid(tables[i]); } function resizableGrid(table) { const row = table.getElementsByTagName("tr")[0]; const cols = row ? row.children : undefined; if (!cols || cols.length === 0) return; table.style.overflow = "hidden"; table.style.tableLayout = "fixed"; // 关键:启用固定布局,强制使用设置的列宽 // 初始化列宽:基于表格100%宽度均分,排除边框占用 const tableWidth = table.offsetWidth; const totalBorder = parseInt(getStyleVal(table, "border-left-width")) * 2 + (cols.length - 1) * parseInt(getStyleVal(cols[0], "border-left-width")); const availableWidth = tableWidth - totalBorder; const initColWidth = availableWidth / cols.length; for (let i = 0; i < cols.length; i++) { cols[i].style.width = `${initColWidth}px`; cols[i].style.minWidth = "50px"; // 设置最小列宽,避免缩至消失 cols[i].style.position = "relative"; const div = createDiv(table.offsetHeight); cols[i].appendChild(div); setListeners(div); } function setListeners(div) { let pageX, curCol, nxtCol, curColWidth, nxtColWidth; div.addEventListener("mousedown", function (e) { e.preventDefault(); // 防止拖拽时选中文本 curCol = e.target.parentElement; nxtCol = curCol.nextElementSibling; pageX = e.pageX; curColWidth = parseFloat(curCol.style.width); if (nxtCol) nxtColWidth = parseFloat(nxtCol.style.width); }); div.addEventListener("mouseover", function (e) { e.target.style.borderRight = "2px solid #0000ff"; }); div.addEventListener("mouseout", function (e) { e.target.style.borderRight = ""; }); document.addEventListener("mousemove", function (e) { if (!curCol || !nxtCol) return; const diffX = e.pageX - pageX; // 计算新宽度,确保不低于最小限制 const newCurWidth = Math.max(parseFloat(curCol.style.minWidth), curColWidth + diffX); const newNxtWidth = Math.max(parseFloat(nxtCol.style.minWidth), nxtColWidth - diffX); // 仅当两者都满足最小宽度时更新,避免布局错乱 if (newCurWidth >= parseFloat(curCol.style.minWidth) && newNxtWidth >= parseFloat(nxtCol.style.minWidth)) { curCol.style.width = `${newCurWidth}px`; nxtCol.style.width = `${newNxtWidth}px`; pageX = e.pageX; // 更新基准点,消除累积误差 } }); document.addEventListener("mouseup", function () { // 重置状态,避免残留影响 curCol = undefined; nxtCol = undefined; pageX = undefined; nxtColWidth = undefined; curColWidth = undefined; }); } function createDiv(height) { const div = document.createElement("div"); div.style.top = 0; div.style.right = 0; div.style.width = "8px"; div.style.position = "absolute"; div.style.cursor = "col-resize"; div.style.userSelect = "none"; div.style.height = `${height}px`; div.style.zIndex = 10; // 确保拖拽层在最上层,避免被内容遮挡 return div; } function getStyleVal(elm, css) { return window.getComputedStyle(elm, null).getPropertyValue(css); } }
CSS
body { font-family: sans-serif; margin: 20px; } table { border-collapse: collapse; width: 100%; border: 1px solid lightgray; } td, th { text-align: center; border-left: 1px solid lightgray; padding: 0.5rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; /* 避免内容撑开列宽 */ }
HTML
<table> <caption>100%宽度可拖拽列宽表格</caption> <thead> <tr><th>列A</th><th>列B</th><th>列C</th><th>列D</th></tr> </thead> <tbody> <tr><td>内容A1</td><td>内容B1</td><td>内容C1</td><td>内容D1</td></tr> <tr><td>内容A2</td><td>内容B2</td><td>内容C2</td><td>内容D2</td></tr> <tr><td>内容A3</td><td>内容B3</td><td>内容C3</td><td>内容D3</td></tr> </tbody> <tfoot> <tr><th>列A</th><th>列B</th><th>列C</th><th>列D</th></tr> </tfoot> </table>
关键改进点
- 启用
table-layout: fixed:强制表格使用设置的列宽,而非自适应内容,这是100%宽度表格可控列宽的核心。 - 初始化均分列宽:根据表格总宽度计算初始列宽,确保初始状态下总宽度为100%。
- 完善拖拽逻辑:
- 支持向左/向右拖拽,保证当前列与下一列的宽度总和不变,维持表格总宽度。
- 设置列宽最小值,避免列被缩至消失或重叠。
- 更新拖拽基准点,消除累积误差导致的布局偏移。
- 增强交互体验:增大拖拽区域宽度,提升拖拽层层级,添加文本溢出处理避免内容撑开列宽。
行高拖拽扩展
若需支持行高拖拽,逻辑与列宽类似:
- 在每行底部添加横向拖拽条。
- 监听鼠标事件,调整当前行(或当前行+下一行)的高度,并设置最小行高限制。
内容的提问来源于stack exchange,提问作者D'arganatan
相关产品推荐
相关产品推荐

