如何用原生JS替换HTML的<li>标签并将内容包裹在<li-text>中
问题
需求:将以下HTML中的每个<li>标签改造为<li><li-text>{li内容}</li-text>结构,仅使用原生JS,禁止使用jQuery。
原HTML代码:
<ul><li>one</li><li>two<ul><li>three<ul><li>four<ul><li>five</li></ul></li></ul></li></ul></li></ul>
当前尝试的JS代码未达预期:
var html = `<ul><li>one</li><li>two<ul><li>three<ul><li>four<ul><li>five</li></ul></li></ul></li></ul></li></ul>`.replace(/<li[^>]*>/g,'<li><li-text>$&</li-text>')
错误结果:列表内容未被正确包裹在<li-text>标签内,生成的HTML如下:
<ul><li><li-text><li></li-text>one</li><li><li-text><li></li-text>two<ul><li><li-text><li></li-text>three<ul><li><li-text><li></li-text>four<ul><li><li-text><li></li-text>five</li></ul></li></ul></li></ul></li></ul>
解决方案
正则处理嵌套HTML结构容易出现逻辑漏洞,更可靠的方式是使用原生DOM API来操作:
// 1. 解析HTML字符串为DOM对象 const html = `<ul><li>one</li><li>two<ul><li>three<ul><li>four<ul><li>five</li></ul></li></ul></li></ul></li></ul>`; const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); // 2. 获取所有li元素(包含嵌套层级) const allLis = doc.querySelectorAll('li'); // 3. 遍历处理每个li allLis.forEach(li => { const liText = doc.createElement('li-text'); // 将li内的所有子节点(文本/嵌套元素)移动到li-text中 while (li.firstChild) { liText.appendChild(li.firstChild); } // 将li-text放回li li.appendChild(liText); }); // 4. 转换回HTML字符串 const resultHtml = doc.body.innerHTML; console.log(resultHtml);
方案优势
- DOM API能正确识别嵌套结构,不会像正则那样出现匹配错误
- 逻辑清晰,直接操作节点移动,完全符合需求
如果坚持使用正则(仅适用于结构规范的HTML),可以用递归匹配的方式:
function wrapLiText(html) { return html.replace(/<li([^>]*)>([\s\S]*?)<\/li>/g, (match, attrs, content) => { // 递归处理嵌套的li内容 const wrappedContent = wrapLiText(content); return `<li${attrs}><li-text>${wrappedContent}</li-text></li>`; }); } const html = `<ul><li>one</li><li>two<ul><li>three<ul><li>four<ul><li>five</li></ul></li></ul></li></ul></li></ul>`; const resultHtml = wrapLiText(html); console.log(resultHtml);
内容的提问来源于stack exchange,提问作者Noor AlManasrah
相关产品推荐
相关产品推荐

