data-*属性名必须全小写加连字符,否则浏览器直接忽略;dataset是只读映射,修改需用setAttribute;不可存储敏感信息或大段JSON。

data-* 属性名必须全小写加连字符,否则浏览器直接忽略
浏览器解析 HTML 时,对 data-* 属性名有硬性校验:只接受 data- 后紧跟小写字母、数字或连字符(-),且不能以数字开头。任何大写字母、下划线(_)、点号(.)、空格或特殊符号,都会导致该属性不被识别——不是读不到,是压根没进 DOM 树。
常见错误现象:data-userId、data_user_id、data-User-Id 在 DevTools 的 Elements 面板里完全看不到;用 el.getAttribute('data-userId') 返回 null;el.dataset.userId 也是 undefined。
-
data-user-id→ ✅ 合法,对应el.dataset.userId -
data-api-url→ ✅ 合法,对应el.dataset.apiUrl -
data-2024-start-date→ ✅ 合法(数字在中间或末尾可),但只能用el.dataset["2024StartDate"]访问 -
data-user_id、data-user.id、data-UserID→ ❌ 全部无效
dataset 映射规则:连字符自动转驼峰,但数字开头必须方括号访问
dataset 是只读映射,它的命名转换是浏览器自动做的,不是 JS 约定。你写 data-user-id,它就转成 userId;写 data-http-status-code,就变成 httpStatusCode。但这个转换有边界:
- 连字符后紧跟大写字母?不存在——浏览器只认小写,所以
data-user-Id不会转成userId,而是被丢弃 - 数字开头如
data-1st-place→ 转为el.dataset["1stPlace"],点语法el.dataset.1stPlace语法错误 - 纯数字如
data-123→ 不合法(data-后不能只跟数字),浏览器不解析
验证方式很简单:在控制台执行 Object.keys(el.dataset),看返回的键名是否符合预期。
立即学习“前端免费学习笔记(深入)”;
修改 data 属性必须用 setAttribute,dataset 赋值无效
el.dataset.foo = 'bar' 看似能运行,但不会更新 HTML 属性,也不会触发 DOM 变更观察(MutationObserver),后续用 getAttribute('data-foo') 仍返回旧值。这是因为 dataset 是只读代理,不是真实属性引用。
- ✅ 正确写法:
el.setAttribute('data-user-id', '1002') - ✅ 读取字符串值:
el.getAttribute('data-user-id')(最可靠,绕过 dataset 映射) - ✅ 读取结构化数据:
JSON.parse(el.getAttribute('data-config'))(避免 dataset 自动转字符串丢失类型) - ❌ 错误操作:
el.dataset.userId = '1002'—— DOM 不变,下次getAttribute还是原值
data-* 不是状态容器,别存敏感信息或大段 JSON
data-* 设计初衷是存静态、轻量、非敏感的上下文元数据,比如 data-track-id="button-submit" 或 data-item-index="5"。它暴露在 HTML 源码里,服务端渲染时也会透出,没有任何保密能力。
- ❌ 别存 token、密码、用户手机号、完整用户对象
- ❌ 别塞超过 1KB 的 JSON 字符串(影响 HTML 体积和解析性能)
- ✅ 小型配置可存,但建议先
JSON.stringify再setAttribute,读取时再JSON.parse - ✅ SSR 场景下,框架(如 React/Vue)默认不透传
data-*,需显式配置data-*: true类选项
最易被忽略的一点:很多人把 data-* 当作“轻量 state”,结果在事件回调里反复读写,却忘了它本质是字符串快照——没有响应性,也没有生命周期管理。真要驱动 UI 变化,还是得靠真正的状态系统。



















