- 前端
- UI组件
【免费下载链接】fast
The adaptive interface system for modern web experiences.
本文围绕 @microsoft/fast-element 1.x API 文档中的SlottedBehavior.disconnect()方法,讲解 FAST Element 的 slotted 节点观察机制中"断开观察"这一关键环节:它的签名约定、在观察生命周期中所处的位置、底层实现原理,以及它与新版SlottedDirective的演进关系。读完本文,你将理解 slot 节点观察从observe()建立到disconnect()拆除的完整闭环,并能在自己的组件模板中正确使用和释放基于<slot>的节点观察能力。
文档原文:disconnect() 的 API 约定
在 fast-element.slottedbehavior.disconnect.md 这份由 API Documenter 自动生成的参考文档中,SlottedBehavior.disconnect()方法被定义为:
- 所属类型:
SlottedBehavior类的方法(该类继承自NodeObservationBehavior<SlottedBehaviorOptions>,详见 fast-element.slottedbehavior.md); - 职责描述:Disconnects observation of the nodes —— 断开对节点的观察;
- 方法签名:
disconnect(): void;- 返回值:
void,即该方法不返回任何值,只负责清理观察所建立的连接。
作为对照,同系列文档中它的"镜像"方法observe()被描述为 "Begins observation of the nodes"(开始观察节点),签名同样为observe(): void;,参见 fast-element.slottedbehavior.observe.md。observe()与disconnect()一一对应:观察的建立与拆除、事件监听的注册与移除,是 slot 节点观察机制中必须成对出现的一组操作。
认识 SlottedBehavior:它观察什么
在深入disconnect()之前,先明确SlottedBehavior在 FAST Element 组件模型中的角色。根据 API 文档,SlottedBehavior的构造函数签名是:
constructor(target: HTMLSlotElement, options: SlottedBehaviorOptions);target:要观察的<slot>元素(HTMLSlotElement);options:观察配置,见 fast-element.slottedbehavioroptions.md。
其配置接口SlottedBehaviorOptions<T = any>同时继承了两组能力:
export interface SlottedBehaviorOptions<T = any> extends NodeBehaviorOptions<T>, AssignedNodesOptions {}其中NodeBehaviorOptions提供property(观察到的节点要赋值到的属性名)与可选的filter(节点过滤函数);AssignedNodesOptions提供浏览器原生HTMLSlotElement.assignedNodes()的选项(如flatten是否扁平化展开嵌套 slot)。也就是说,SlottedBehavior的本质是:持续观察某个<slot>的 assignedNodes(被分配节点)集合,并在集合变化时把最新节点列表写入宿主组件指定属性。类上的三个方法各司其职,完整清单见下表(方法明细分别见 构造函数、getNodes 与 observe):
| 方法 | 签名 | 职责 |
|---|---|---|
(constructor) | (target: HTMLSlotElement, options: SlottedBehaviorOptions) | 创建实例,绑定被观察的 slot 与配置 |
observe() | observe(): void | 开始观察节点(注册监听) |
getNodes() | protected getNodes(): Node[] | 从 slot 取回应被赋值给目标的节点 |
disconnect() | disconnect(): void | 断开对节点的观察(移除监听) |
disconnect() 在观察生命周期中的位置
SlottedBehavior的观察不是一次性的快照,而是一个"建立 → 更新 → 拆除"的持续过程:
- 建立:
observe()被调用,开始在<slot>上注册slotchange事件监听——slot 的 assignedNodes 一旦因 DOM 变更而重新分配,就会触发该事件; - 更新:事件触发后,行为重新调用
getNodes()取得最新节点,经filter过滤后写入options.property指定的属性; - 拆除:
disconnect()被调用,移除事件监听,观察彻底终止。
disconnect()处于这一生命周期的末端,承担资源释放与副作用清理职责。它不返回值(void),也不改变任何节点本身——它改变的只是"观察关系"这一状态:让行为对象与目标 slot 之间不再存在监听连接。
一个值得注意的语义细节是:disconnect()只负责停止后续的观察通知。在当前仓库中与之一脉相承的指令实现里,解除绑定时还会先将被观察节点列表重置为空数组、再执行断开,从而保证解除绑定后既不会继续收到更新,也不会残留旧数据——这一点在 node-observation.ts 的unbind()中体现得很清楚(详见下文源码对照)。
源码对照:disconnect 的底层实现原理
需要说明的是:当前仓库主体对应 FAST Element 3.x 代码,1.x 的SlottedBehavior(继承NodeObservationBehavior)类源码已不在本仓库内;但仓库 fast-element-2 迁移文档 明确指出,SlottedBehavior/ChildrenBehavior在后续版本中被SlottedDirective/ChildrenDirective取代,二者承担完全相同的职责。因此可以用 3.x 中等价的SlottedDirective源码,来精确还原disconnect()断开观察的底层机制。
在 slotted.ts 中,slot 观察依赖原生事件:
const slotEvent = "slotchange";SlottedDirective的observe()与disconnect()成对实现:
observe(target: EventSource): void { target.addEventListener(slotEvent, this); } disconnect(target: EventSource): void { target.removeEventListener(slotEvent, this); }这正是SlottedBehavior.disconnect()在 1.x 中实际执行的逻辑:从目标<slot>元素上移除slotchange事件监听(对应的 1.x API 文档描述即 "Disconnects observation of the nodes")。由于监听器函数就是指令/行为实例自身(this实现了handleEvent),addEventListener与removeEventListener传入完全相同的引用,保证监听能够被精确移除。
抽象基类 node-observation.ts 则定义了断开观察的调用契约:disconnect被声明为受保护抽象方法,任何节点观察指令(slotted、children 共用此基类)都必须实现它。同时,该基类展示了断开动作在完整解绑流程中的顺序:
unbind(controller: ViewController): void { const target = controller.targets[this.targetNodeId] as any; this.updateTarget(controller.source, emptyArray); // 1. 节点列表重置为空 this.disconnect(target); // 2. 断开观察(移除监听) target[this._controllerProperty] = null; // 3. 清理控制器引用 }可以看到,disconnect()是解绑(unbind)三步清理中的第二步:先把数据置空、再断监听、最后清引用。这种顺序保证了即使观察期间有残留事件排队,也不会在解绑后继续向已失效的控制器回调。
用测试验证断开行为
仓库中的 Playwright 测试 slotted.pw.spec.ts 对断开观察的行为做了完整的端到端验证。其中 "clears and unwatches when unbound"(解绑时清空并停止观察)测试精确复现了disconnect()的预期效果:
- 创建宿主元素、shadowRoot 与
<slot>,构造 10 个子节点; - 用
new SlottedDirective({ property: "nodes" })绑定模型,断言model.nodes与子节点一一对应; - 调用
behavior.unbind(controller)—— 内部会执行disconnect(); - 断言解绑后
model.nodes.length === 0(节点列表被清空); - 继续向宿主追加新的子节点并等待更新队列(
await Updates.next()),断言model.nodes仍为空——证明监听已被彻底移除,后续 slotchange 不再触发回调。
另一个相关测试 "should not throw if DOM stringified" 则展示了slotted在模板中的典型用法及解绑的健壮性:
const template = html` <slot id="test" ${slotted("nodes")} ${ref("reference")}> </div> `; const view = template.create(); view.bind(model); view.unbind();该测试证明,slotted指令(1.x 中即SlottedBehavior的前身用法)在view.unbind()触发disconnect()之后,组件状态依然可被安全序列化(JSON.stringify),不会抛出异常——即断开观察不会破坏模型对象。
实战:在模板中使用并正确释放 slotted 观察
在 1.x 中,SlottedBehavior通常由模板编译器通过slotted指令生成,开发者无需直接调用disconnect();但理解它的行为对正确使用至关重要。典型用法如下:
import { html, slotted, elements } from "@microsoft/fast-element"; // 组件模板:把 slot 中分配的元素写入组件的 nodes 属性 const template = html` <slot ${slotted({ property: "nodes", filter: elements("li") })}></slot> `;对应的模型类:
class MyList extends HTMLElement { nodes: Node[]; // slotted 行为会把分配的节点数组持续写入该属性 }property: "nodes"指定观察结果写入的属性;filter: elements("li")只保留<li>元素(elements工厂函数来自 node-observation.ts,未传 selector 时仅过滤出元素节点)。
当该组件的模板视图被销毁(如view.unbind()或组件从 DOM 中移除),框架会依次触发updateTarget置空、disconnect()移除slotchange监听,从而防止内存泄漏与对已卸载组件的无效更新。这也是为什么disconnect()虽是void方法,却在生命周期中不可或缺。
1.x 到 2.x 的演进:SlottedBehavior 与 SlottedDirective
若你正在从 1.x 升级,请留意 fast-element-2 迁移文档 中的说明:1.x 的SlottedBehavior与ChildrenBehavior已被 2.x 起的SlottedDirective与ChildrenDirective取代。变更的动机在于指令复用——旧的行为对象为每个模板实例单独创建,而新指令允许单个指令实例跨所有使用它的模板实例共享。在 slotted.ts 中,slotted()工厂函数接收属性名或完整配置对象并返回SlottedDirective,其disconnect()语义与 1.x 的SlottedBehavior.disconnect()完全一致(均为移除slotchange监听)。API 层面的替换细节还可参考 CHANGELOG.md。
小结
SlottedBehavior.disconnect()是 FAST Element 1.x slot 节点观察机制中"拆除"一环的正式 API:
- 签名
disconnect(): void,返回空值,职责单一——断开对节点的观察; - 与
observe()成对出现,底层实现是从目标<slot>移除slotchange事件监听(可对照 3.x slotted.ts 中的SlottedDirective.disconnect验证); - 在解绑流程中按"置空数据 → 断开监听 → 清理引用"的顺序执行(见 node-observation.ts);
- 后续版本中由
SlottedDirective承接其职责,行为语义不变。
对于使用<slot>组合 Shadow DOM 内容、并希望把分配节点同步到响应式属性的 FAST Element 开发者,理解observe/disconnect这对生命周期方法,是写出无泄漏、可卸载、可复用的组件模板的基础。
- 前端
- UI组件
【免费下载链接】fast
The adaptive interface system for modern web experiences.
相关推荐
FAST 子节点观察运行时:@microsoft/fast-element 中 ChildrenBehavior 的完整解析
FAST 子节点观察运行时:@microsoft/fast element 中 ChildrenBehavior 的完整解析 本文基于仓库中 fast elem
前端UI组件Fast-Element children() 指令详解:在 FASTElement 中观察与同步子节点
Fast Element children 指令详解:在 FASTElement 中观察与同步子节点 children 是 @microsoft/fast el
前端UI组件深入解析 fast-element 的 `ChildrenBehavior.observe()`:子节点观察的启动机制与运行时原理
深入解析 fast element 的 ChildrenBehavior.observe :子节点观察的启动机制与运行时原理 本篇技术指南聚焦于 @micros
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考