data-*属性不能存选中状态,仅存初始值;真实状态须用checked、aria-selected等dom属性或js变量维护,否则刷新丢失、类型错乱、css不响应。

data-* 属性不能保存“选中状态”,它只存初始值;页面交互产生的状态变化必须靠 JavaScript 变量或 DOM 属性(如 checked、aria-selected)维护,否则刷新就丢、跨组件不同步、类型错乱。
为什么 data-active="true" 不能当真实选中状态用
浏览器把 data-active 当作纯字符串元数据,不参与任何语义逻辑。你点击按钮后执行 el.dataset.active = "false",看起来变了,但:
-
el.getAttribute("data-active")可能仍返回旧值(dataset 赋值不保证同步写入 DOM) - 刷新页面后,DOM 重载,JS 修改全部丢失,只剩 HTML 里写的初始值
-
data-active="false"读出来是字符串"false",if (el.dataset.active)恒为真(非空字符串转布尔为 true) - CSS 选择器
[data-active="true"]不会响应 JS 的 dataset 赋值,必须用setAttribute()才触发重匹配
真正该用什么存选中状态
按场景分,选对载体比硬塞 data-* 更可靠:
- 表单控件(
input[type="checkbox"]、radio):直接读写checked属性,浏览器原生支持、可回车聚焦、无障碍友好 - 自定义按钮/菜单项:用
aria-selected="true"+ CSS[aria-selected="true"],语义正确且屏幕阅读器可识别 - 需要持久化(如记住上次选中):存到
localStorage或sessionStorage,而不是反复操作 DOM 上的 data-* - React/Vue 组件内:用
useState或ref管理状态,data-* 仅用于透传 ID 或 class 名等静态标识
data-* 唯一适合的“状态”类用途
它只适合那些「从 DOM 结构就能推导、无需跨元素同步、也不需持久化」的瞬态标记:
- 折叠面板当前是否展开:
<div data-expanded="true">,配合 CSS <code>max-height和 JS 切换setAttribute("data-expanded", "false") - 表格行编辑模式:
<tr data-editing="true">,仅影响该行内部 input 显示,保存后立即清除<li>Tab 栏当前激活项:<code><button data-tab-id="profile" data-active="true"></button>,仅用于 CSS 样式高亮,切换时用setAttribute("data-active", "false")清掉旧项 -
命名非法:写成
data-userId或data_user_id,浏览器直接忽略,dataset.userId和getAttribute("data-userId")全部返回undefined -
读取方式错:一上来就用
dataset.active,遇到data-2024-active或data-api-key就失效;应优先用getAttribute("data-2024-active") -
写入方式错:只写
el.dataset.active = "false",但后续getAttribute("data-active")还是"true",CSS 也不变——必须用el.setAttribute("data-active", "false")
注意:所有这些场景都要求你手动调用 setAttribute() 更新,而不是只改 dataset;也要求你每次读取时做类型判断,比如 el.getAttribute("data-active") === "true",而非 el.dataset.active。
常见翻车点:命名、读取、写入全错位
90% 的 data-* 问题出在这三处:
最稳组合:写用 setAttribute(),读用 getAttribute(),命名只用小写字母+连字符,数字开头的属性一律加引号并用方括号访问。











