open是布尔属性,只检测存在与否;设open="false"仍展开;JS应操作open属性而非setAttribute;监听状态用toggle事件;无原生禁用方案。

open 属性不是开关,只看“有没有”
open 是布尔属性,浏览器只检测它是否存在,不解析值。写 open="false" 或 open="" 甚至 open="banana",只要属性名出现了,就等价于展开——这是最常踩的坑。
-
<details open></details>→ 展开 -
<details open="false"></details>→ 依然展开(⚠️别这么写) -
<details></details>→ 收起(没写就是没存在)
JavaScript 动态控制必须读写 open 属性,不能用 setAttribute
DOM 元素的 open 属性是反射属性,和实际状态实时同步。用 setAttribute 会把字符串值写进 HTML 属性,反而触发“存在即展开”逻辑。
- ✅ 正确:
el.open = false、console.log(el.open) - ❌ 错误:
el.setAttribute('open', 'false')→ 实际强制展开 - ❌ 错误:
el.hasAttribute('open')≠el.open:初始没写时两者都是false;但执行el.open = true后,hasAttribute仍返回false(HTML 源码没变)
监听展开/收起变化只能用 toggle 事件
<details></details> 没有 change 事件。用户点击 <summary></summary> 切换状态后,触发的是 toggle 事件,此时读 el.open 才是最新值。
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- ✅ 正确:
el.addEventListener('toggle', () => console.log(el.open)) - ❌ 错误:
el.addEventListener('change', ...)→ 不会触发 - 注意:事件在状态切换完成后派发,不需要手动判断前后差异
默认展开但想禁用用户交互?没有原生方案
HTML 规范没提供 disabled 或 readonly 属性给 <details></details>。强行禁用得靠 JS 拦截点击,但要注意副作用:
立即学习“前端免费学习笔记(深入)”;
- 拦截
click在<summary></summary>上可能影响键盘焦点和屏幕阅读器行为 - 更稳妥的做法是移除
<summary></summary>的交互语义(比如换成<div>),但会丢失可访问性支持 <li>如果只是视觉上“看起来不可点”,CSS 加 <code>pointer-events: none更轻量,但无法阻止键盘Enter或Space触发


















