data-*属性只支持字符串,JSON需手动序列化与解析;写入用JSON.stringify(),读取用JSON.parse()并加try/catch;推荐命名如data-json-user,注意引号转义。

data-* 属性只能存字符串,JSON 必须序列化
HTML 的 data-* 属性原生只支持字符串值,直接赋值 { "id": 1, "name": "Alice" } 会被自动转成 [object Object]——这是最常见的误用起点。浏览器不会帮你做 JSON 序列化或反序列化,这一步必须手动完成。
正确做法是:写入前用 JSON.stringify(),读取后用 JSON.parse()。注意空值、undefined、函数、Date 对象等无法被 JSON 安全序列化的类型会直接报错或丢失。
-
undefined、function、Symbol、BigInt在JSON.stringify()中会被忽略或抛错 - 含循环引用的对象会触发
TypeError: Converting circular structure to JSON - 推荐在
JSON.parse()外层加try/catch,避免因 HTML 被篡改或手误导致解析失败而阻断逻辑
如何安全地写入和读取 data-json 风格属性
别用 data-user 这种模糊命名,建议统一用 data-json-xxx(如 data-json-user)明确语义,也方便后续正则或工具识别。写入时注意引号嵌套问题——HTML 属性值本身用双引号,内部 JSON 字符串需转义双引号或改用单引号包裹。
示例:
<div id="item" data-json-user='{"id":1,"name":"Alice","tags":["admin","active"]}'>...><p>对应 JS 读取逻辑:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill10595" title="htmlppt.skill"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d79f23518.jpg" alt="htmlppt.skill" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill10595" title="htmlppt.skill" class="overflowclass">htmlppt.skill</a>
<p class="overflowclass">把任意文章或文档内容转换成精美的全屏翻页 HTML 演示文件(幻灯片风格)。当用户发来一篇文章、文档链接、Markdown 内容、或粘贴的文本,并且希望生成演示用的 HTML 时触发。支持任意内容来源:iWiki 链接、KM 链接、本地文件路径、直接粘贴的文本。生成的 HTML 文件保存到本地工作区,并通过企微直接发送给用户。触发词示例:帮我把这篇文章做成PPT、转成演示文档、生成HTML幻灯片、做个演示、转成可以演示的格式、article to deck、make a slide。</p>
</div>
<a rel="nofollow" href="/xiazai/skill10595" title="htmlppt.skill" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<pre class="brush:php;toolbar:false;">const el = document.getElementById('item');<br>let user;<br>try {<br> user = JSON.parse(el.dataset.jsonUser);<br>} catch (e) {<br> console.warn('Failed to parse data-json-user:', e.message);<br> user = null;<br>}
dataset API 对连字符命名的自动转换规则
dataset 是个“驼峰化”代理对象,它把 data-json-user 自动映射为 dataset.jsonUser,把 data-api-url 映射为 dataset.apiUrl。但这个转换不处理大写字母后的连字符,也不支持数字开头或纯数字键名——比如 data-123-id 无法通过 dataset.123Id 访问(语法错误),得改用 getAttribute('data-123-id')。
- 连字符(
-)后紧跟字母 → 首字母大写,如data-user-info→dataset.userInfo - 连续多个连字符(如
data-foo--bar)会被当作一个分隔符,结果仍是dataset.fooBar -
data-json→dataset.json(合法),但data-json-2024→dataset.json2024(可读,但易与年份混淆,建议避免)
为什么不用 innerHTML 或自定义属性代替 data-*?
有人图省事把 JSON 塞进 innerHTML 或自定义属性(如 el.myData = {...}),但这破坏了数据与 DOM 的分离原则,且无法被 SSR、爬虫或 DevTools 的 Elements 面板直接查看。更重要的是:dataset 是标准 API,支持 CSS 属性选择器(如 [data-json-user])、无障碍属性继承、以及未来可能的 declarative shadow DOM 兼容性。
真正需要警惕的是体积——单个 data-* 值不宜超过几 KB。过长的 JSON 会导致 HTML 文件膨胀、解析变慢,且 Chrome DevTools 在 Elements 面板中默认截断长 dataset 值,调试困难。若数据量大,应考虑用 <script type="application/json"></script> 块或 fetch 加载。
实际项目里最常被忽略的点:服务端渲染时没对 JSON 字符串做 HTML 实体转义,导致引号冲突或 XSS 漏洞。务必用服务端模板的安全输出函数(如 Nunjucks 的 |safe 或 EJS 的 )或手动替换 " 为 "。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










