data-* 属性必须用短横线分隔,不能用驼峰;dataset 是只读的 DOMStringMap,修改需用 setAttribute();获取值恒为字符串,需手动类型转换;含下划线等非法字符或需保留空白时应使用 getAttribute()。
HTML5 允许在任意元素上添加以 data- 开头的自定义属性,但命名有硬性规则:只能用小写字母、数字、短横线(-),且必须至少有一个短横线。比如 data-user-id 合法,datauserid 或 dataUserId 都不合法——浏览器会忽略后者,前者甚至不会被解析进 dataset。
原因在于 DOM 解析时,会把短横线后的字母自动转为驼峰形式映射到 dataset 对象上。所以:
data-user-id → dataset.userId
data-api-url → dataset.apiUrl
data-abc-def-ghi → dataset.abcDefGhi
element.dataset 返回的是一个 DOMStringMap,看起来像普通对象,但它是只读代理。直接赋值如 el.dataset.foo = 'bar' 不会报错,但也不会生效;刷新页面后值就丢了。
要真正更新 DOM 属性,必须用 setAttribute():
el.setAttribute('data-foo', 'new-value');反过来,用 setAttribute() 更新后,dataset.foo 会立刻反映新值。这个单向同步关系常被误认为“双向绑定”,实际只是读取时自动映射。
无论你在 HTML 里写 data-count="42" 还是 data-active="true",通过 dataset.count 或 dataset.active 拿到的都是字符串 "42" 和 "true",不是数字或布尔值。
常见踩坑场景:
if (el.dataset.active === true) → 永远 falseel.dataset.count + 1 → "421"(字符串拼接)正确做法是显式转换:
const count = Number(el.dataset.count);
const isActive = el.dataset.active === 'true';
dataset 对短横线转驼峰的规则很严格,遇到 data-user-name 可以转成 dataset.userName,但一旦属性名含下划线、点号或连续短横线(如 data-user_name),dataset 就无法访问——它压根不会出现在对象里。
此时必须用传统方式:
el.getAttribute('data-user_name'); // 正确
// el.dataset.user_name → undefined另外,如果值里含前后空格或换行符,dataset 会自动 trim,而 getAttribute() 返回原始字符串。对格式敏感的场景(比如 base64、JSON 片段),优先选后者。