最稳妥的显示方式是用 iframe;动态创建并设 srcdoc 属性可内联渲染同源 HTML 字符串,跨域则需后端配置 CORS 或 frame-ancestors,IE 不支持 srcdoc 时可用 Blob URL 降级,局部渲染推荐 DOMParser 解析后挂载 body 子节点。

用 iframe 直接嵌入最省事,但要注意同源和安全限制
如果后端返回的是完整 HTML 字符串(比如 fetch 拿到的是一段含 <html><body>... 的文本),直接写进 innerHTML 会丢掉 script、style 和事件绑定,也不执行 JS。最稳妥的显示方式是用 iframe。
实操建议:
- 动态创建
iframe,设srcdoc属性填入 HTML 字符串(支持同源内联渲染) - 若接口跨域,且返回的是真实 HTML 页面(不是字符串),可直接设
src为接口 URL,但需后端配Access-Control-Allow-Origin或允许 iframe 嵌入(X-Frame-Options/Content-Security-Policy: frame-ancestors) -
srcdoc不支持 IE,如需兼容 IE,得降级用 Blob +URL.createObjectURL构造 blob URL
DOMParser 解析 HTML 字符串再挂载,适合局部渲染
当只需要显示 HTML 片段(比如一段富文本内容),且不依赖原页面的 JS 或全局样式时,DOMParser 是更轻量的选择——它能把字符串转成真实的 DOM 节点,保留结构和属性。
常见错误现象:
立即学习“前端免费学习笔记(深入)”;
- 直接
el.innerHTML = htmlStr后,<script>标签不执行,<link>或<style>不生效 - 用
DOMParser解析后忘了把body子节点 append 进去,而是 append 了整个document对象
正确做法:
- 用
new DOMParser().parseFromString(htmlStr, 'text/html') - 取
parsed.body.children或parsed.body.childNodes,再逐个appendChild - 注意:解析出的脚本默认不执行,如真需要,得手动提取
<script>内容并eval(不推荐)或创建新script标签插入
后端返回 HTML 字符串时,前端别漏掉字符转义和 XSS 防御
很多接口“返回 HTML”其实是返回一个 JSON 字段,值是 HTML 字符串(如 { "content": "<div onclick=alert(1)>..." })。这时候直接插进页面等于开后门。
使用场景:
- CMS 富文本内容下发
- 邮件模板预览
- 第三方生成的报告页片段
关键提醒:
- 如果内容可信(如自家后台编辑器产出),至少做基础过滤:
DOMPurify.sanitize(htmlStr) - 如果内容不可信(如用户提交),绝不能用
innerHTML或srcdoc;应服务端渲染成纯文本,或前端只解析白名单标签(如marked渲染 Markdown) - Chrome 最新版对
srcdoc中的javascript:协议已拦截,但老浏览器仍可能触发 XSS
React/Vue 项目里显示 HTML 字符串,别硬套 v-html 或 dangerouslySetInnerHTML
框架层封装了安全机制,但开发者常忽略上下文。比如在 React 中写 {dangerouslySetInnerHTML: { __html: apiRes }},看着简洁,实际埋雷。
性能与兼容性影响:
- 每次更新都触发整块 HTML 重解析,无法利用虚拟 DOM diff,滚动/动画易卡顿
- Vue 的
v-html会清空元素内所有响应式绑定,子组件、指令、事件监听全失效 - SSR 场景下,
dangerouslySetInnerHTML在服务端渲染时不会执行 script,前后端不一致
替代思路:
- 把 HTML 字符串交给专门的渲染组件(如
react-html-parser,可配置 tag 映射为 React 组件) - 后端改用结构化数据(如 AST 或 Markdown),前端用统一渲染器,兼顾安全与可维护性


















