HTML 的 data-* 自定义属性,是前端开发里非常实用的一类属性。它可以把少量业务数据直接挂在元素上,让 HTML 和 JavaScript 之间传递信息更方便。比如按钮对应的商品 ID、列表项的状态、弹窗触发目标、统计埋点参数,都可以用 data-* 表达。
很多项目里会看到 data-id、data-type、data-target 这样的写法,但如果不了解命名规则、读取方式和适用边界,也很容易把它用成“万能数据仓库”。本文从基础语法讲起,再到 JavaScript 读取和实际场景,帮你把 data-* 用得更稳。
基本语法
data-* 属性的写法是在普通 HTML 元素上添加以 data- 开头的属性名,后面跟自定义名称。属性值本质上是字符串。
<button data-id="1001" data-type="primary">查看详情</button>
上面的按钮保存了两个信息:data-id 表示业务 ID,data-type 表示按钮类型。浏览器不会把这些属性当成特殊功能处理,但 JavaScript 可以很方便地读取它们。
命名规则
data-* 的属性名建议使用小写字母、数字和短横线。不要使用大写字母,也不要写成太复杂的命名。保持短、清楚、可读,是最重要的原则。
<div data-user-id="88" data-order-status="paid">订单信息</div>
当 JavaScript 通过 dataset 读取时,短横线命名会转换成驼峰命名。比如 data-user-id 会变成 dataset.userId,data-order-status 会变成 dataset.orderStatus。

dataset 读取
读取 data-* 最常用的方式是使用元素的 dataset 对象。它会把所有 data- 开头的属性映射成可访问的属性。
<button id="detailBtn" data-product-id="1001" data-category="server">查看详情</button>
const button = document.querySelector('#detailBtn');
console.log(button.dataset.productId);
console.log(button.dataset.category);
需要注意,dataset 读取出来的值都是字符串。即使你写的是 data-product-id="1001",读取出来也是字符串 "1001",如果要做数字计算,需要手动转换。
getAttribute 读取
除了 dataset,也可以使用 getAttribute() 读取完整属性名。这个方式更直接,适合属性名需要动态拼接,或者你想保持和 HTML 属性名完全一致的场景。
const value = button.getAttribute('data-product-id');
dataset 更简洁,getAttribute() 更通用。日常开发中,如果只是读取固定的 data-* 字段,优先用 dataset;如果需要操作任意属性,再考虑 getAttribute()。
修改属性值
data-* 不只能读取,也可以通过 JavaScript 修改。修改 dataset 的值后,HTML 元素上的对应属性也会同步变化。
button.dataset.productId = '2002';
button.dataset.status = 'active';
上面的代码会把按钮上的 data-product-id 改成 2002,并新增 data-status="active"。如果想删除某个数据,可以使用 delete。
delete button.dataset.status;
事件委托场景
data-* 经常和事件委托一起使用。比如列表里有很多按钮,每个按钮对应不同数据,不需要给每个按钮单独绑定事件,只要在父元素上监听点击,再读取被点击按钮的 data-id。
<ul id="productList">
<li><button data-id="101">查看 A</button></li>
<li><button data-id="102">查看 B</button></li>
</ul>
const list = document.querySelector('#productList');
list.addEventListener('click', (event) => {
const button = event.target.closest('button[data-id]');
if (!button) return;
const id = button.dataset.id;
console.log('当前点击 ID:', id);
});
这种写法适合动态列表。即使列表项后续通过接口追加,新按钮也能被同一个父级监听器处理,不需要重复绑定事件。
组件状态标记
在简单交互组件里,data-* 也可以用来标记状态。例如折叠面板、标签页、筛选项等,都可以用 data-state、data-active 这类属性描述当前状态。
<button class="tab" data-tab="basic" data-active="true">基础信息</button>
<button class="tab" data-tab="price" data-active="false">价格配置</button>
不过状态如果变得复杂,最好交给组件状态管理或 JavaScript 数据结构,不要把所有状态都堆进 DOM 属性。data-* 更适合轻量标记,不适合承载复杂业务模型。
CSS 选择器
data-* 还可以用于 CSS 属性选择器。比如根据状态改变样式,或者选择某类元素。
[data-active="true"] {
color: #1677ff;
font-weight: 600;
}
button[data-type="danger"] {
color: #d93026;
}
这种方式可读性不错,但不要滥用。CSS 负责表现层,如果某个属性只是为了样式,也可以考虑 class。通常来说,class 更适合样式控制,data-* 更适合保存和元素相关的数据。
不要存敏感信息
data-* 写在 HTML 里,用户可以直接通过浏览器开发者工具看到。因此不要把敏感信息放进去,比如用户 token、接口密钥、后台权限标识、隐私数据等。
它只适合保存前端交互需要的非敏感数据。只要你不希望用户看到或篡改,就不要放在 data-* 里。权限判断、安全校验、价格计算等关键逻辑必须放在后端。
适用边界
适合使用 data-* 的场景包括:按钮携带 ID、列表项携带类型、弹窗触发器携带目标、埋点元素携带事件名、筛选项携带筛选值。它们都有一个共同点:数据量小,而且和当前 DOM 元素强相关。
不适合的场景包括:大段 JSON、完整用户信息、复杂配置对象、接口返回的完整业务数据。数据一旦变多,就应该放在 JavaScript 状态、接口响应或专门的数据层里,而不是塞进 HTML 属性。
实践建议
写 data-* 时,先问三个问题:这个数据是否和当前元素强相关?是否只是少量非敏感信息?是否需要被 CSS 或 JavaScript 快速读取?如果答案都是肯定的,用 data-* 很合适。
如果只是为了样式,用 class 更直接;如果是复杂业务数据,用 JavaScript 数据结构更清晰;如果涉及安全和权限,必须放到后端校验。把边界分清楚,data-* 就会成为非常顺手的小工具,而不是难维护的隐形数据仓库。














暂无评论内容