JS递归DOM处理函数为何未处理段落标签?需保留li提取文本
问题:递归函数未处理段落标签,p及code标签未被替换为纯文本的原因
需求说明
仅保留HTML中的li标签,其余标签仅保留文本内容。
现有JS代码
let html = ` <ol> <li><a href="#"><code>foo</code> link text</a>;</li> <li><a href="#"><code>bar</code> link text</a>;</li> </ol> <p>Paragraph text <code>baz</code> and <code>biz</code> text.</p> <p>Paragraph text.</p> `; html = `<body>${html}</body>`; let parsed = new DOMParser().parseFromString( html, 'text/html' ); function testFn( node ) { node.childNodes.forEach( function( e ) { testFn( e ); if ( e.nodeType !== Node.ELEMENT_NODE ) return; if ( e.nodeName.toLowerCase() !== 'li' ) { e.replaceWith( ...e.childNodes ); } }); } testFn( parsed.body ); console.log( parsed.body.innerHTML );
运行结果
<li>foo link text;</li> <li>bar link text;</li> <p>Paragraph text <code>baz</code> and <code>biz</code> text.</p> <p>Paragraph text.</p>
预期结果
<li>foo link text;</li> <li>bar link text;</li> Paragraph text baz and biz text. Paragraph text.
问题原因分析
1. HTML转义导致DOM解析异常(代码示例中的关键错误)
你的代码里用<和>转义了所有HTML标签,包括包裹内容的<body>。DOMParser解析这类转义字符串时,会把它们当作纯文本内容而非实际的DOM元素。这就导致<p>和<code>都只是文本字符串,不会被识别为元素节点,自然无法触发替换逻辑。
要正确解析成DOM结构,需使用未转义的标签(直接写<body>而非<body>)。
2. 递归遍历的逻辑缺陷(核心问题)
假设修正了转义问题,原代码仍可能出现<p>未被替换的情况,原因是:
node.childNodes是动态更新的NodeList,当你替换某个节点(比如把<ol>换成<li>),会实时改变父节点的子节点结构,导致forEach遍历跳过后续部分节点。- 原函数的处理顺序是先递归处理子节点,再判断当前节点是否替换。但对于
<p>这类节点,当完成子节点处理后,动态变化的NodeList可能导致替换逻辑未被正确触发。
修正后的代码
改用反向遍历(避免动态NodeList的影响),确保所有非li元素都被正确替换:
let html = ` <ol> <li><a href="#"><code>foo</code> link text</a>;</li> <li><a href="#"><code>bar</code> link text</a>;</li> </ol> <p>Paragraph text <code>baz</code> and <code>biz</code> text.</p> <p>Paragraph text.</p> `; html = `<body>${html}</body>`; let parsed = new DOMParser().parseFromString(html, 'text/html'); function testFn(node) { // 反向遍历,避免动态NodeList导致的节点丢失 for (let i = node.childNodes.length - 1; i >= 0; i--) { const e = node.childNodes[i]; testFn(e); if (e.nodeType !== Node.ELEMENT_NODE) continue; if (e.nodeName.toLowerCase() !== 'li') { e.replaceWith(...e.childNodes); } } } testFn(parsed.body); console.log(parsed.body.innerHTML);
内容的提问来源于stack exchange,提问作者Pavel Rozhdestvenskiy
相关产品推荐
相关产品推荐

