不能直接监听 toggle 事件——它仅原生作用于 元素;自定义组件需手动管理 open 属性、dispatch 带 composed: true 的 toggle 事件,并用 CSS 过渡实现动画。

Web Component 实现折叠组件时,直接监听 toggle 事件是行不通的——toggle 是 <details></details> 元素的原生事件,不是自定义元素默认触发的。你得自己定义交互逻辑、管理展开状态,并手动 dispatch 事件或暴露属性接口。
为什么不能直接用 toggle 事件监听自定义折叠组件
浏览器只对内置的 <details></details> 元素在用户点击 <summary></summary> 时触发 toggle 事件。你的 <my-accordion></my-accordion> 或 <collapsible-section></collapsible-section> 是继承 HTMLElement 的自定义类,不自动获得该行为。试图写 element.addEventListener('toggle', ...) 不会响应任何动作。
-
toggle事件不在 Custom Elements 规范的默认生命周期中 - 即使你手动
dispatchEvent(new Event('toggle')),它也不会像原生<details></details>那样联动 DOM 展开/收起(因为没 Shadow DOM 内部结构绑定) - 外部 JS 调用
element.open = true也不会自动触发该事件,除非你显式实现
open 属性与 opened 属性:哪个该用作状态源
选 open —— 它是 HTML 原生语义,和 <details></details> 对齐,支持布尔属性写法(<my-collapse open></my-collapse>),且能被 attributeChangedCallback 自动捕获。用 opened 会割裂语义,也增加转换成本。
- 在
static get observedAttributes()中声明['open'] - 在
attributeChangedCallback里同步内部<div> 的 <code>hidden属性或 CSS 类 - 设置
this.open = true时,应同时调用this.setAttribute('open', ''),否则 attribute 观察器不会触发 - 避免仅靠 JS 属性控制状态,否则 SSR 渲染或初始 HTML 中的
open特性会被忽略 - 监听内部按钮的
click,调用this.toggle()方法 -
toggle()方法内部:取反当前this.hasAttribute('open'),再setAttribute或removeAttribute - 紧接着
dispatchEvent(new Event('toggle', { bubbles: true, composed: true })),让事件穿透 Shadow DOM - 不要在
click处理器里直接改this.open = !this.open(这是 JS 属性,不触发 attribute 观察器)
如何封装点击切换逻辑并通知外部
把点击区域(如 <slot name="trigger"></slot> 或内部 <button></button>)的 click 事件处理写死在组件内,然后统一更新状态 + dispatch 自定义事件。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
立即学习“前端免费学习笔记(深入)”;
示例关键片段:
toggle() {
if (this.hasAttribute('open')) {
this.removeAttribute('open');
} else {
this.setAttribute('open', '');
}
this.dispatchEvent(new Event('toggle', { bubbles: true, composed: true }));
}
折叠动画怎么加才不卡、不闪、不破坏 Shadow DOM 封装
别用 display: none 切换——它无法过渡。要用 max-height + overflow: hidden,配合 JS 动态计算内容高度,或者更稳妥地用 height: 0 + padding: 0 + opacity: 0 组合过渡。
- 在
render()或updateStyles()中,根据open状态给内部容器设不同 class(如collapsible--open/collapsible--closed) - CSS 中写:
.collapsible--closed { height: 0; padding: 0; opacity: 0; overflow: hidden; transition: all 0.25s ease-in-out; } - 确保
transition只作用于可动画属性,避免transform或visibility单独使用(前者无布局变化,后者不可过渡) - 如果内容高度动态,需在
connectedCallback后用getBoundingClientRect().height获取真实高度再设max-height,但注意这会触发重排
最易被忽略的一点:composed: true 必须加在 toggle 事件 dispatch 中,否则父级页面监听不到;而很多人只写了 bubbles: true 就以为够了。


















