details标签无原生只读属性,需用js监听details的click和keydown事件,在summary被点击或按space/enter时调用preventdefault()阻止切换,同时可动态设置open属性控制状态。

details标签默认不支持只读属性,得靠JS模拟
details 标签本身没有 readonly 或 disabled 属性,浏览器也不响应对它的直接禁用。所谓“只读展开”,实际是阻止用户点击 summary 切换 open 状态,但保留内容可选、可复制、可聚焦(如内部有 input 时仍需操作)。
用 preventDefault 阻止 summary 点击事件最可靠
监听 details 的 click 事件,在 summary 被点中时调用 event.preventDefault(),就能拦住默认的展开/收起行为。注意必须监听在 details 上,而不是单独给 summary 绑事件——因为点击 summary 会冒泡触发 details 的 click,且原生行为由 details 自己处理。
实操建议:
- 用
event.target.matches('summary')精准判断是否点中了 summary,避免误拦其他子元素点击 - 不要用
pointer-events: none或user-select: none替代——前者会让内部文本无法选中,后者完全不影响点击行为 - 若需动态切换只读状态,用一个布尔变量控制是否执行
preventDefault,别反复 add/remove 事件监听器
const el = document.querySelector('details');
let isReadOnly = true;
el.addEventListener('click', (e) => {
if (isReadOnly && e.target.matches('summary')) {
e.preventDefault();
}
});
设置 open 属性后,JS 修改仍生效但用户点不动
open 是可写属性,JS 可随时设为 true 或 false,比如 el.open = false 会强制收起。这点和只读逻辑不冲突:JS 控制的是状态,而 preventDefault 控制的是用户交互入口。常见场景包括:
- 表单提交后禁用所有 details,但需先收起已展开项
- 根据 API 响应结果,初始设为
open=true,再立即锁死交互 - 配合 CSS 动画:先 JS 设
open=true,再用 transition 实现淡入,此时用户点 summary 不会打断动画
注意:直接写 HTML 的 <details open></details> 和 JS 设置 el.open = true 效果一致,但前者在 JS 执行前就渲染为展开态;后者更可控,适合条件初始化。
focus 和键盘操作也要一并拦截
仅拦鼠标点击不够。用户可能用 Tab 键聚焦到 summary,再按 Space 或 Enter 触发展开。所以得补充键盘事件:
- 监听
keydown,对summary元素捕获Space和Enter键 - 用
e.preventDefault()阻止默认行为,同时e.stopPropagation()防止冒泡到details再触发 click - 别忘了
summary默认可聚焦,如果不想它出现在 tab 顺序里,加tabindex="-1"(但会影响可访问性,慎用)
el.querySelector('summary').addEventListener('keydown', (e) => {
if (isReadOnly && (e.code === 'Space' || e.code === 'Enter')) {
e.preventDefault();
e.stopPropagation();
}
});
有些开发者试图用 pointer-events: none + user-select: text 混搭来“半只读”,结果发现移动端 Safari 对 pointer-events 支持不稳定,且空格键依旧能触发。真正跨浏览器稳住的,还是事件拦截 + 显式控制 open 属性这两手。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











