JavaScript遍历动态变化DOM数组时元素丢失的解决方案
问题:DOM节点移动导致遍历遗漏的简洁解决方法
需要将原表单<table>中的<tr>元素根据其innerText分发到对应目标<table>,但使用forEach遍历原table的childNodes时,移动元素会导致节点数组动态变化,部分元素被遗漏。求无需复杂索引操作的简洁解决办法。
初始结构
<table id='tableForm'><tbody> <tr><td>Some Input to stay here</td></tr> <tr><td>Some Input to stay here</td></tr> <tr><td>Some Input to move to tab1</td></tr> <tr><td>Some Input to move to tab2</td></tr> <tr><td>Some Input to stay here</td></tr> <tr><td>Some Input to move to tab2</td></tr> <tr><td>Some Input to move to tab1</td></tr> </tbody></table> <table id='tab1'> <tbody></tbody> </table> <table id='tab2'> <tbody></tbody> </table>
目标结构
<table id='tableForm'><tbody> <tr><td>Some Input to stay here</td></tr> <tr><td>Some Input to stay here</td></tr> <tr><td>Some Input to stay here</td></tr> </tbody></table> <table id='tab1'><tbody> <tr><td>Some Input to move to tab1</td></tr> <tr><td>Some Input to move to tab1</td></tr> </tbody></table> <table id='tab2'><tbody> <tr><td>Some Input to move to tab2</td></tr> <tr><td>Some Input to move to tab2</td></tr> </tbody></table>
现有代码(存在问题)
var toMove = { 'Input to move to tab1' : 'tab1', 'Input to move to tab2' : 'tab2', } $('table#tableForm')[0].firstChild.childNodes.forEach((c) => { content = $(c).find('td')[0].innerText if (toMove[content]) { $('#'+toMove[content]).appendTo(c) // <= 此处appendTo参数写反,且遍历动态NodeList会导致遗漏 } });
简洁解决方案
方案1:将动态NodeList转为静态数组遍历
把原table的childNodes转换成静态数组,遍历的是原节点集合的副本,不受DOM节点移动的影响:
var toMove = { 'Some Input to move to tab1': 'tab1', 'Some Input to move to tab2': 'tab2' }; // 用Array.from将动态NodeList转为静态数组 Array.from($('#tableForm tbody')[0].childNodes).forEach((node) => { // 跳过文本节点(换行、空格等) if (node.nodeType !== 1) return; const content = $(node).find('td').text().trim(); const targetId = toMove[content]; if (targetId) { // 修正appendTo方向:将当前<tr>追加到目标table的tbody中 $(node).appendTo(`#${targetId} tbody`); } });
方案2:使用jQuery的.each()遍历
jQuery的.each()会一次性获取所有匹配元素并存储在静态集合中,遍历过程不受DOM变化影响,代码更简洁:
var toMove = { 'Some Input to move to tab1': 'tab1', 'Some Input to move to tab2': 'tab2' }; // 直接选择所有<tr>元素,用each遍历 $('#tableForm tbody tr').each(function() { const content = $(this).find('td').text().trim(); const targetId = toMove[content]; if (targetId) { $(this).appendTo(`#${targetId} tbody`); } });
关键修正点
- appendTo参数方向:原代码写反了,应该是
$(c).appendTo(target),而非target.appendTo(c); - 匹配文本一致性:
toMove的键名要和<td>实际文本完全匹配(原代码少了Some前缀,会导致匹配失败); - 过滤文本节点:
childNodes会包含换行、空格等文本节点,需判断nodeType === 1(元素节点)再处理(方案2用jQuery选择器直接选<tr>,自动跳过文本节点)。
内容的提问来源于stack exchange,提问作者Arano
相关产品推荐
相关产品推荐

