HTML 里的 data-* 自定义属性到底该不该用怎么用
结论:data-* 该用,但它只负责一件事——承载"属于这个元素、只给前端自己看"的数据。拿它做组件配置、状态钩子和 CSS 选择器最合适;拿它当全局数据仓库、替代语义化属性或 aria-*,就是误用。
data-* 属性和 id、class 有什么区别?
结论:data-* 是 HTML5 规范定义的自定义数据属性,浏览器不会解释它的值,辅助技术(屏幕阅读器)也不会读它,唯一消费者是你自己的 JS 和 CSS。
规范对命名有三条硬要求:属性名不能含大写 ASCII 字母(data-userName 会被解析成 data-username)、不能以 xml 开头、多个单词建议用连字符分隔(data-user-name)。JS 侧通过 element.dataset 访问,连字符会转成驼峰:data-user-name → dataset.userName,data-post-id → dataset.postId。注意 dataset 在 IE11 才支持,IE10 及更早只能用 getAttribute('data-user-name')。
和 id、class 的分工很清楚:id 管唯一标识和锚点,class 管样式分组,data-* 管挂数据。三者不要互相兼职。
data-* 怎么读写删?具体写法是什么
结论:读用 dataset.xxx 或 getAttribute(),写用 dataset.xxx = 值,删用 delete dataset.xxx 或 removeAttribute(),值永远是字符串。
<button id="btn" data-action="like" data-post-id="42">赞</button>
const btn = document.querySelector('#btn');
btn.dataset.action; // "like"
btn.dataset.postId; // "42" —— 是字符串,不是数字
Number(btn.dataset.postId); // 42,要算数必须显式转换
btn.dataset.state = 'loading'; // 写入 → data-state="loading"
btn.dataset.userName = 'ann'; // 写入 → data-user-name="ann"
delete btn.dataset.state; // 删除该属性
btn.removeAttribute('data-post-id'); // 等价的删除写法
CSS 里同样能用它当选择器和伪元素文案源:
[data-state="loading"] { opacity: .5; }
.tip::after { content: attr(data-tip); }
什么时候该用 data-*,什么时候不该用
结论:满足"数据属于这个元素 + 只给前端用 + 不承担语义"三条就放心用,缺一条就换方案。
适合用的场景:组件配置(data-placement="top")、状态钩子(data-state="open")、CSS 选择器和 attr() 文案、埋点标识(data-track="buy")、渐进增强时给脚本传初始参数。
不该用的场景有四个,都踩过坑:
- 本来就有语义属性。要禁用就写
disabled,要必填就写required,不要造data-disabled。屏幕阅读器需要知道的状态必须用aria-expanded、aria-hidden,data-*不进无障碍树。 - 大块数据。把一段 20KB 的 JSON 塞进属性,页面体积直接翻倍,每次读取都要重新解析属性字符串;应该改用
<script type="application/json">加JSON.parse。 - 敏感信息。属性在页面源码、右键"检查"、DevTools 里一览无余,token、手机号、内部 ID 别往里放。
- 跨组件共享的状态。那是状态管理或模块变量的职责,硬塞进 DOM 只会让数据流变脏。
用 data-* 最容易踩的坑有哪些
结论:坑集中在类型、命名和缓存三处。
- 值全是字符串:
data-count="10"里dataset.count是"10",+ 1会得到"101"。老实用Number()或parseInt(x, 10)。 - 驼峰反向写不进去:
dataset.userName = 'x'生成的是data-user-name,所以dataset['user-name']永远读不到值。 - 把布尔当布尔:
data-active="false"依然"存在"这个属性,[data-active]选择器照样命中。判断必须写dataset.active === 'true'。 - jQuery 的
.data()有缓存:用attr()改了属性,.data()可能还返回旧值;新项目直接用原生dataset或框架的 props 更省心。 - 高频读写:在
mousemove、scroll回调里反复读写dataset会带来额外开销,把值取出来缓存到局部变量再用。
一句话收束:把 data-* 当成"元素级、前端私有、值为字符串"的数据袋来用,符合这三条就上,不符合就换 aria-*、语义属性、class 或内嵌 JSON。
原文链接:https://www.gj0.com/thread-777.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。