xmlserializer序列化html dom时输出非原始源码,因其生成标准化、语法合法的html字符串,会自动补全标签、转义字符、移除注释、统一自闭合形式,不保留空格、引号风格或作者意图。

XMLSerializer 序列化 HTML DOM 时为什么输出不是你写的源码?
直接用 XMLSerializer 处理 document 或任意 Element,得到的永远是「规范化的 XML/HTML 字符串」,而非原始手写源码。它会自动补全缺失标签(如 <tbody>)、标准化属性顺序、转义字符、移除注释和 IE 条件注释,并把自闭合标签(如 <code><img>)统一为 <img> 形式——这不是 bug,是设计使然。
所以别指望它还原 <div class="a b">hello</div> 的空格或引号风格;它只保证语法合法、结构等价。
用 new XMLSerializer().serializeToString() 正确序列化 DOM 节点
这是最常用也最安全的方式,适用于现代浏览器(Chrome 1+、Firefox 2+、Safari 3.1+、Edge 12+),但不支持 IE9 及以下。
-
XMLSerializer只接受Node实例(Element、Document、DocumentFragment),不能传字符串或 HTML 文本 - 对
document序列化会包含根节点;若只要 body 内容,传document.body - 若节点含动态插入的 shadow DOM,
serializeToString()不会包含它(仅序列化 light DOM) - 示例:
const serializer = new XMLSerializer(); const htmlStr = serializer.serializeToString(document.getElementById('app'));
遇到 innerHTML 比 serializeToString() 更“像源码”?那是错觉
element.innerHTML 看似更贴近手写风格(比如保留单引号、不补 <tbody>),但它本质是浏览器解析后生成的「反向渲染快照」,受当前 DOM 状态影响极大:
<ul>
<li>执行过 <code>el.style.color = 'red' 后,innerHTML 不会体现该样式,但 serializeToString() 也不会——两者都不保存运行时属性
el.setAttribute('x', ''),innerHTML 会显示转义后的值,而 serializeToString() 同样转义,行为一致innerHTML 的序列化逻辑松散(如 Firefox 早期版本不补 <colgroup></colgroup>),但这不可靠,也不可移植innerHTML 不是源码备份,只是轻量替代方案;需要语义保真(如测试 DOM 结构断言),必须用 XMLSerializer
想保留注释、doctype 或自定义格式?得自己劫持或封装
XMLSerializer 硬编码忽略 Comment 节点和 DocumentType 节点(除非你显式传入 document.doctype 单独序列化)。实时回流中若需完整源码级输出,只能手动拼接:
- 先用
serializer.serializeToString(document.documentElement)获取主体 - 用
document.doctype判断是否存在,存在则手动拼(注意名称、publicId、systemId 字段需自行处理) - 遍历
document.childNodes,对Node.COMMENT_NODE类型单独提取textContent并插入对应位置——但位置无法精确还原,因注释在解析后已脱离原始父子链 - 格式化(缩进/换行)必须额外用库(如
js-beautify)或正则,XMLSerializer原生不提供
也就是说,“实时回流 + 规范源码”本身是个矛盾需求:规范意味着标准化,而源码意味着保留作者意图。真正要还原编辑器里的原始输入,唯一可靠路径是监听 input 或保存初始 textContent,而不是依赖序列化接口。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











