浏览器原生解析器仅保留命名合规的data-*属性(全小写+连字符),并同时存入DOM属性列表和映射到dataset;命名不合规(如data-userId)则dataset静默忽略,getAttribute仍可读取原始值。

浏览器原生解析器怎么处理 data-* 属性
浏览器会完整保留 data- 开头的属性,只要命名合规(全小写 + 连字符),就存进 DOM 属性列表,同时自动映射到 dataset 对象。比如 <div data-user-id="123"></div>,el.getAttribute('data-user-id') 和 el.dataset.userId 都能取到 "123"。
但注意:命名不合规就静默失效。写成 data-userId、data_user_id 或 data-UserID,dataset 里完全找不到,getAttribute() 却可能拿到值——因为原生属性没被删,只是映射失败。
- 必须以
data-开头,后接小写字母、数字或连字符(不能以数字开头) -
dataset是只读代理,改它不改 DOM;真要更新 HTML,必须用setAttribute('data-user-id', '456') - 值永远是字符串,
dataset.price是"299.99",不是数字;布尔值如data-active="true"也得手动转
HTML Purifier 等服务端净化库为什么删掉非 data- 属性
它不是“解析完再删”,而是在构建 DOM 树前就按白名单裁剪属性。默认配置下,my-id、x-status 这类非标准属性根本不会进入 DOM 树——连 getAttribute() 的机会都没有。
data- 属性天然在白名单里,不用额外配置;若硬要用 my-id,得显式加进 HTMLDefinition,还要指定类型(比如 CDATA),否则仍被丢弃。
立即学习“前端免费学习笔记(深入)”;
- HTML Purifier 不校验语法,只做白名单过滤;
data-是唯一被默认放行的自定义通道 - 即使你在 HTML 里写了
<div my-id="123"></div>,净化后变成<div></div>,无警告、无报错 - 服务端模板输出前若经过净化,前端 JS 就永远看不到那个属性——别指望靠
getAttribute()补救
DOMPurify 和 jsdom 对非 data- 属性的行为差异
DOMPurify 默认只放行标准属性 + data- 系列;jsdom 更宽松,原样保留所有属性,但“保留”不等于“可用”。
比如 <div my-id="123"></div> 在 jsdom 里:el.getAttribute('my-id') 能取到,但 el.myId 是 undefined;在 DOMPurify 里,默认直接剔除,除非你手动加白名单:
DOMPurify.sanitize(html, { ADD_ATTR: ['my-id'] })但光加名字不够,还得配类型,否则仍被过滤:
DOMPurify.addHook('uponSanitizeAttribute', (node, data) => {
if (data.attrName === 'my-id') data.keepAttr = true;
});-
DOMPurify的ADD_ATTR只控制是否保留,不控制值合法性;恶意值(如javascript:alert(1))仍需配合ADD_URI_SAFE_ATTR或自定义 hook -
jsdom保留属性但不提供语义映射,dataset、CSS 选择器、无障碍 API 全部忽略它 - 服务端用
lxml.html解析时,elem.attrib有my-id,但若后续把结果喂给前端再过一遍DOMPurify,就又丢了
为什么 data-* 是唯一全链路兼容的私有通道
不是因为它更“安全”,而是浏览器、框架(Vue/React SSR)、净化库(HTMLPurifier/DOMPurify)、服务端解析器(jsdom/lxml)全都认它。其他自定义属性每过一层都可能消失,且消失方式不同:有的静默忽略,有的报错拒绝,有的保留但不可访问。
真正容易被忽略的点是:属性能不能留到最后,不取决于你写的 HTML 对不对,而取决于**紧贴你代码下游的那个解析环节**。比如 CMS 输出的 HTML 经过净化 → SSR 渲染 → 浏览器加载,中间任何一环不认你的 my-id,它就断了。
data- 属性名写错一个字母,整个数据就拿不到;值存 JSON 却忘了 JSON.parse(getAttribute()),拿到的就是字符串;用 dataset.foo = 'bar' 改完发现 DevTools 里 HTML 没变——这些都不是边缘 case,是每天都在发生的实际问题。



















