JavaScript HTML表格排序异常:新表格点击后页面无响应
表格排序函数导致页面无响应问题排查与修复
问题现象
- 已有JavaScript排序函数可正常对第一个HTML表格(
tableBeingDecomm)进行排序 - 对第二个表格(
PortsTable)执行排序时,无报错但页面直接无响应
相关代码
正常工作的表格代码
<table id="tableBeingDecomm" align="center" render-area="beingDecom"> <thead> <tr> <th id="beingDecom"><a href="#"> Server Name <img src='/icons/sort.png' width='20' height='20' style='display:inline;'> </a></th> <th id="beingDecomDate"><a href="#"> Deleting Date <img src='/icons/sort.png' width='20' height='20' style='display:inline;'> </a></th> </tr> </thead> <tbody render-action="loop"> <tr render-data="jsonBeingDecomm"> <td>{!serverName!}</td> <td>{!deletingDate!}</td> </tr> </tbody> </table>
导致问题的表格代码
<table id="PortsTable" align="center" render-area="dcPorts"> <thead> <tr> <th id="ServerNameHeader1"><a href="#"> Server Name <img src='/icons/sort.png' width='20' height='20' style='display:inline;'> </a></th> <th id="ServerNameHeader2"><a href="#"> Destination <img src='/icons/sort.png' width='20' height='20' style='display:inline;'> </a></th> <th>Port 53</th> <th>Port 88</th> <th>Port 135</th> <th>Port 139</th> <th>Port 389</th> <th>Port 445</th> <th>Port 464</th> <th>Port 636</th> </tr> </thead> <tbody render-action="loop"> <tr render-data="jsonPorts"> <td>{!Server Name!}</td> <td>{!Destination!}</td> <td>{!Port 53!}</td> <td>{!Port 88!}</td> <td>{!Port 135!}</td> <td>{!Port 139!}</td> <td>{!Port 389!}</td> <td>{!Port 445!}</td> <td>{!Port 464!}</td> <td>{!Port 636!}</td> </tr> </tbody> </table>
原排序函数代码
function sortTable(tableId, column) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById(tableId); switching = true; dir = "asc"; while (switching) { switching = false; rows = table.rows; for (i = 1; i < (rows.length - 1); i++) { shouldSwitch = false; x = rows[i].getElementsByTagName("td")[column]; y = rows[i + 1].getElementsByTagName("td")[column]; if (!isNaN(x.innerHTML) && !isNaN(y.innerHTML)) { if (dir == "asc") { if (Number(x.innerHTML) > Number(y.innerHTML)) { shouldSwitch= true; break; } } else if (dir == "desc") { if (Number(x.innerHTML) < Number(y.innerHTML)) { shouldSwitch= true; break; } } } else { if (dir == "asc") { if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) { shouldSwitch= true; break; } } else if (dir == "desc") { if (x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) { shouldSwitch= true; break; } } } } if (shouldSwitch) { rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; switchcount ++; } else { if (switchcount == 0 && dir == "asc") { dir = "desc"; switching = true; } } } } let sortOrder = "asc";
调用代码
document.getElementById("ServerNameHeader1").addEventListener("click", function() { sortTable("PortsTable", 0); }); document.getElementById("ServerNameHeader2").addEventListener("click", function() { sortTable("PortsTable", 1); });
问题原因分析
- 无限循环触发:函数每次执行都会重置
dir = "asc",忽略外部sortOrder变量。当表格存在大量重复内容时,升序排序完成后switchcount为0,会触发切换为降序并重新循环;但降序排序同样因重复内容导致switchcount为0,又切换回升序,陷入无限循环,直接导致页面无响应。 - 行范围处理错误:
table.rows包含thead和tbody的所有行,循环从i=1开始但用rows.length -1做判断,会遗漏最后一行的比较。 - 排序逻辑不严谨:使用
innerHTML可能受HTML标签干扰,数字判断仅用isNaN存在误判情况。
修复方案
修改后的排序函数
// 为每个表格独立维护排序状态,避免跨表格冲突 const tableSortStates = {}; function sortTable(tableId, column) { var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0; table = document.getElementById(tableId); // 初始化当前表格的排序方向,默认升序 if (!tableSortStates[tableId]) { tableSortStates[tableId] = "asc"; } dir = tableSortStates[tableId]; switching = true; while (switching) { switching = false; // 仅获取tbody中的数据行,避免处理thead行 rows = table.tBodies[0].rows; // 循环覆盖所有相邻数据行的比较 for (i = 0; i < (rows.length - 1); i++) { shouldSwitch = false; x = rows[i].getElementsByTagName("td")[column]; y = rows[i + 1].getElementsByTagName("td")[column]; // 处理文本内容,去除前后空格,避免干扰排序 const xValue = x.textContent.trim(); const yValue = y.textContent.trim(); // 准确判断是否为数字类型 const isXNumber = !isNaN(xValue) && !isNaN(parseFloat(xValue)); const isYNumber = !isNaN(yValue) && !isNaN(parseFloat(yValue)); if (isXNumber && isYNumber) { const xNum = parseFloat(xValue); const yNum = parseFloat(yValue); // 根据当前排序方向判断是否需要交换 shouldSwitch = dir === "asc" ? xNum > yNum : xNum < yNum; } else { const xStr = xValue.toLowerCase(); const yStr = yValue.toLowerCase(); shouldSwitch = dir === "asc" ? xStr > yStr : xStr < yStr; } if (shouldSwitch) break; } if (shouldSwitch) { rows[i].parentNode.insertBefore(rows[i + 1], rows[i]); switching = true; switchcount++; } else { // 更新当前表格的排序方向 tableSortStates[tableId] = dir === "asc" ? "desc" : "asc"; // 无交换发生时直接跳出循环,避免无限循环 break; } } }
关键改进点
- 新增
tableSortStates对象,为每个表格独立维护排序方向,避免全局变量冲突 - 直接获取tbody中的数据行,简化循环起始索引,避免处理thead行
- 使用
textContent.trim()替代innerHTML,排除HTML标签和空格对排序的干扰 - 优化数字判断逻辑,使用
parseFloat确保准确识别数字类型 - 修改循环结束逻辑:无交换发生时直接切换排序方向并跳出循环,彻底避免无限循环
内容的提问来源于stack exchange,提问作者sigfried
相关产品推荐
相关产品推荐

