data属性只能存字符串,对象必须用json.stringify()序列化后存入、用json.parse()解析读取,并加try/catch容错;键名遵循kebab-case转camelcase规则;适合存轻量静态数据,避免嵌套深、体积大或需响应式更新的数据。

data属性只能存字符串,对象必须序列化
HTML 的 dataset API 不支持直接存 JavaScript 对象——浏览器会自动调用 toString(),结果通常是 [object Object],后续无法还原。必须手动序列化再反序列化。
常见错误现象:
– 给元素设置 data-user="{name: 'Alice', id: 123}",读取后得到字符串,但没做 JSON.parse() 就当对象用 → 报错 Cannot read property 'name' of undefined
– 使用 JSON.stringify() 时没处理单引号、换行或特殊字符 → HTML 解析失败或属性截断
- 始终用
JSON.stringify()序列化对象,再赋值给data-xxx - 读取时必须用
JSON.parse(),且要加try/catch(用户可能手动改了 HTML 或数据损坏) - 避免在对象里放函数、
undefined、Date、RegExp等无法 JSON 序列化的值
用 element.dataset 操作时注意键名转换规则
JavaScript 访问 dataset 时,连字符命名(kebab-case)会转为驼峰(camelCase),比如 data-user-info → element.dataset.userInfo。但反向赋值不触发自动转换,必须严格匹配。
使用场景:动态写入用户配置、表单项元数据、渲染前的初始状态等。
- 写入:
el.dataset.userInfo = JSON.stringify({id: 456, role: 'admin'});→ 生成data-user-info='{"id":456,"role":"admin"}' - 读取:
const info = JSON.parse(el.dataset.userInfo || '{}');(|| '{}'防空字符串解析报错) - 如果 key 含数字或大写字母(如
data-User1),JS 中不能用点语法访问,得用方括号:el.dataset['User1']
不要把复杂对象塞进 data 属性,小心性能和可维护性
data 属性适合存轻量、静态、结构简单的数据(如 ID、状态码、简单配置)。一旦对象嵌套深、体积大(>1KB)、或需频繁更新,就会拖慢 DOM 解析、增加内存开销,也难调试。
性能影响:
– 大字符串反复 JSON.parse() 占用主线程时间
– 浏览器对长 data 属性的序列化/反序列化没有优化
– DevTools 查看时展开困难,容易误判 DOM 结构
- 超过 3 层嵌套或含数组的对象,优先考虑用
Map或闭包缓存,而非 data 属性 - 需要响应式更新的数据,改用
CustomElement的私有属性或状态管理库 - 若必须存,压缩前先用
JSON.stringify(obj, null, 0)去掉空格,减小体积
服务端渲染时,data 属性里的 JSON 要防 XSS 和转义
后端模板(如 EJS、Jinja)拼接 JSON 到 data- 属性时,若未正确转义,会导致 HTML 解析中断或执行恶意脚本。
错误示例:<div data-config="<%= JSON.stringify(user) %>"> —— 当 <code>user.name 是 foo<script>alert(1)</script>,就出问题。
- Node.js 中用
serialize-javascript替代裸JSON.stringify,它会自动转义和 Unicode 控制符 - PHP 用
json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP) - 前端自己拼接时,永远用
element.setAttribute('data-xxx', JSON.stringify(obj)),别用 innerHTML 插入
JSON.parse() 缺少容错,以及把 data 属性当成通用状态容器滥用。DOM 属性不是 Store,该放 JS 变量的地方别硬塞进去。











