最安全准确的方式是用 DOMParser 解析 HTML 字符串为文档后取 innerText;它自动处理嵌套、自闭合标签、大小写混用、特殊字符,且忽略 script/style、不执行 JS、无 XSS 风险。

用 DOMParser 解析 HTML 字符串再取 innerText
直接对 HTML 字符串调用 innerText 会报错,因为字符串不是 DOM 节点。必须先解析成真实文档结构,再读取渲染后文本。
这是目前最安全、语义最准的方式,能自动处理嵌套、自闭合、大小写混用、属性含 > 或引号等所有合法变体,且天然忽略 <script> 和 <style> 内容,不执行 JS,无 XSS 风险。
实操建议:
- 始终用
DOMParser的text/html类型解析,不要用text/xml,否则遇到<br>等自闭合标签会报错 -
doc.documentElement.innerText是推荐读取路径;doc.body?.innerText在某些空文档中可能为undefined - 若需兼容老 IE(已极少见),改用临时
div+innerHTML+textContent,但要注意textContent不跳过隐藏元素
示例:
立即学习“前端免费学习笔记(深入)”;
function extractPlainText(htmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
return doc.documentElement.innerText || '';
}
extractPlainText('<p>Hello<strong>world</strong></p>'); // → "Helloworld"(注意:innerText 会压缩空白)
textContent vs innerText:选哪个取决于你要什么
textContent 返回 DOM 树中所有文本节点的原始拼接,包括空格、换行、隐藏元素内容;innerText 模拟用户“看见”的文本,会跳过 display: none、visibility: hidden 元素,并压缩连续空白、换行归一为单空格。
常见错误现象:
- 用
textContent提取后发现一堆空行或多余空格,是因为它忠实地保留了 HTML 中的换行与缩进 - 用
innerText却漏掉关键内容,比如某个<div style="display:none">API_KEY=xxx</div>被跳过 - 在 CSS 改变字体或使用
white-space: pre时,innerText行为可能意外变化
使用场景判断:
- 要提取“用户实际看到的正文”→ 选
innerText - 要保留段落边界做分句或后续 NLP 处理→ 选
textContent,再手动 normalize 空白 - 要提取脚本/注释中的调试信息(极少见)→ 只能走
textContent+ 遍历节点,innerText完全无视它们
用 querySelectorAll + textContent 精准控制提取范围
当 HTML 字符串里混着广告栏、侧边栏、页脚等噪声,而你只想要主内容区(如所有 <p>、<h2>、<li>),硬套 innerText 就会把无关文本也拉进来。
此时应放弃“全文提取”,改用选择器定位目标节点,再聚合 textContent:
- 避免用
document.body.querySelectorAll(...)—— 这是针对当前页面 DOM,不是你的 HTML 字符串 - 正确做法:先用
DOMParser解析,再对doc.body或doc.documentElement调用querySelectorAll - 每个匹配节点调用
textContent,而非innerText,防止因样式丢失内容 - 若需去重或过滤空值,用
Array.from(...).map(...).filter(Boolean),别直接对整个字符串split(/\s+/)去重
示例(只取所有段落和二级标题):
function extractMainText(htmlString) {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const nodes = doc.body.querySelectorAll('p, h2');
return Array.from(nodes)
.map(el => el.textContent.trim())
.filter(t => t.length > 0);
}
别用正则删标签:边界 case 多到不可控
像 htmlString.replace(/<[^>]*>/g, '') 这类写法,看似简单,实际在以下情况必然失败:
- HTML 中含 JavaScript 字符串:
<script>console.log("a<b");</script>→ 正则会在"a<处提前截断 - 属性值含
>:<div data-html="<b>test</b>">content</div>→ 正则把整个div当成一个标签删掉 - 注释或 CDATA:
<!-- <p>ignored</p> -->→ 正则无法识别注释边界,可能误删或漏删 - 实体字符:
或被当成普通文本保留,导致结果含乱码
性能上也不占优:正则需多次扫描字符串,而 DOMParser 是浏览器原生 C++ 实现,解析速度更快,内存更可控。
真正需要正则的唯一合理场景:预处理极简 HTML 片段(如仅含 <b>、<i>、<br>),且你 100% 控制输入源——这种场景极少,不值得为它牺牲健壮性。



















