文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
嵌套源于编辑器误将换行识别为新段落且未去重,导致dom中出现内容;应使用queryselectorall('p p')定位并用replacewith提升子节点清理,再过滤空壳。

为什么 <p></p> 会层层嵌套?
Word 粘贴、微信转发、甚至某些富文本编辑器(如早期 TinyMCE、UEditor)在回车或格式化时,会把一个段落反复包装成 <p></p>
<p></p>
<p>内容</p>
<p></p> 套娃,样式继承错乱、光标跳转异常、innerText 提取多出空行。
querySelectorAll('p p') 是识别嵌套的最简方式
别用正则匹配 <p></p> 标签,它无法判断父子关系。真正能定位“被嵌套的 <p></p>”的是 CSS 选择器:
-
document.querySelectorAll('p p')找出所有非顶层的<p></p>(即父元素也是<p></p>的那些) -
document.querySelectorAll('p > p')更严格,只找直接子级嵌套 - 若内容尚未插入文档,先用
DOMParser解析:const doc = new DOMParser().parseFromString(html, 'text/html'),再查doc.querySelectorAll('p p')
用 replaceWith(...) 拆解嵌套,不是删
直接 remove() 会丢内容;用 innerHTML 拼接又容易 XSS。安全做法是把内层 <p></p> 的子节点“提一层”:
const nestedPs = doc.querySelectorAll('p p');
for (const p of nestedPs) {
const fragment = document.createDocumentFragment();
while (p.firstChild) {
fragment.appendChild(p.firstChild);
}
p.replaceWith(fragment);
}
这段代码不会删掉任何文本或子标签(比如 <strong></strong>、<img>),只是把 <p></p>
<p>Hello</p>
<p>Hello</p>。注意:必须用 replaceWith,appendChild 到父节点会引发重复插入。
嵌套清理后,还得防 <p><br></p> 这种空壳
拆完嵌套,常冒出一堆无意义的空 <p></p>,里面只有 <br> 或空白文本节点。它们不影响显示,但干扰 SSR 渲染和 NLP 分词:
- 用
p => p.textContent.trim() === '' && !p.querySelector('img, iframe, svg')判定是否为空壳 - 带
style="margin: 0"或class="empty-para"的也要一并过滤——这些是编辑器加的“占位符” - 不要在遍历时边查边删,先收集节点列表,再倒序
remove(),避免NodeList动态变化导致漏删
真正的难点不在怎么删,而在删完之后要不要补语义:比如把连续多个 <p></p> 合并成一个,还是保留段落间距逻辑——这得看你的 CMS 或 SSR 模板是否依赖 <p></p> 作为段落单元。没想清楚前,宁可留着,也别用正则暴力替换 <p></p>。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










