Lit 如何用 @lit-labs/observers 响应式控制器接入平台 Observer 并管理其生命周期
【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit
如果你在用 Lit 构建组件时,需要感知 DOM 变化、元素尺寸变化、可见性变化或性能指标,平台自带的 MutationObserver、ResizeObserver、IntersectionObserver、PerformanceObserver 都能做到,但手动管理它们的 observe/disconnect 时机容易出错。@lit-labs/observers把这四类平台 Observer 封装成响应式控制器(ReactiveController),你只需在组件里创建控制器实例,它的观察、清理就会跟随宿主组件的连接/断开自动进行,观察到的变化经callback处理后存入value,可以直接在渲染中使用。下面以浏览器端的 Lit 组件为例,说明安装、接入与生命周期管理的完整路径。
安装与引入方式
在项目目录下运行:
$ npm install @lit-labs/observers该包的dependencies为@lit/reactive-element(^1.0.0 || ^2.0.0),在基于lit的组件中使用即可。四个控制器需要按子路径分别引入,而不是从包根导入:
import {MutationController} from '@lit-labs/observers/mutation-controller.js'; import {ResizeController} from '@lit-labs/observers/resize-controller.js'; import {IntersectionController} from '@lit-labs/observers/intersection-controller.js'; import {PerformanceController} from '@lit-labs/observers/performance-controller.js';在组件中创建控制器
构造函数签名为new XxxController(host, {target, config, callback, skipInitial}),其中host是ReactiveControllerHost & Element,通常是ReactiveElement或LitElement实例本身,所以直接传this。仓库文档给出的 MutationController 示例(packages/labs/observers/README.md):
import {MutationController} from '@lit-labs/observers/mutation-controller.js'; // ... class MyElement extends LitElement { private _observer = new MutationController(this, { config: {attributes: true}, }); render() { return html` ${this._observer.value ? `Attributes set!` : ``} `; } }这里config是透传给平台MutationObserver的配置对象,示例只观察属性变化;value由callback的返回值决定,未提供callback时value保持undefined。如果希望value承载业务数据,可以传入callback,其参数与平台回调一致(记录列表、observer 实例),返回值存入value:
private _observer = new MutationController<boolean>(this, { config: {attributes: true, childList: true}, callback: (records, observer) => records.length > 0, });observe/unobserve/disconnect等 API 及四种控制器的差异见 mutation-controller.ts、resize-controller.ts、intersection-controller.ts、performance-controller.ts。
配置项与四种控制器的差异
四个控制器共用的配置项为:
config:透传给平台 Observer 的配置对象。类型随控制器而定:MutationObserverInit、ResizeObserverOptions、IntersectionObserverInit、PerformanceObserverInit。target?: Element | null:要观察的元素。不指定时默认观察host自身;显式设为null则不会自动观察任何目标。除配置target外,还可以随时调用observe(target)追加目标。注意只有配置里指定的target会在 host 重新连接时被重新观察,运行时通过observe()追加的目标不会。callback?:把观察到的变化处理成存入value的值,泛型<T>即value的类型。skipInitial?: boolean:默认在开始观察一个 target 时,callback会先被调用一次(不携带变化),用于帮助初始化状态;设为true可跳过这一步。
各控制器的区别:
| 控制器 | config类型 | 额外说明 |
|---|---|---|
| MutationController | MutationObserverInit(源码接口中为必填) | 检测 DOM 变化,如节点增删、属性改变 |
| ResizeController | ResizeObserverOptions | 检测元素尺寸变化;额外提供target(observe?)元素指令 |
| IntersectionController | IntersectionObserverInit | 检测目标元素与视口/祖先的交叉状态 |
| PerformanceController | PerformanceObserverInit(源码接口中为必填) | 报告 performance API 的 marks、measures 等指标;没有target概念,observe()不带参数 |
unobserve(target)只有 IntersectionController 和 ResizeController 提供;MutationController 与 PerformanceController 不提供。
ResizeController 还支持把观察逻辑直接写在模板里的元素指令target():把指令应用到某个元素上,该元素就会被自动观察;指令被移除、observe参数为false,或宿主/目标元素断开时会自动取消观察。
生命周期是如何被管理的
创建控制器时,构造函数内部会调用host.addController(this)把自己注册到宿主上(见 reactive-controller.ts 中的ReactiveController接口定义)。注册之后,以下钩子随宿主生命周期自动触发:
- host 连接(对应自定义元素的
connectedCallback()):hostConnected()中对每个已配置的 target 调用observe(target),开始观察; - host 断开(对应
disconnectedCallback()):hostDisconnected()调用disconnect(),即平台 observer 的disconnect(); - host 更新后(
hostUpdated(),在客户端更新周期中):通过takeRecords()取出更新期间积压的变更记录并立即经callback处理,保证value是新鲜的。
observer 回调内部处理完变化后会调用host.requestUpdate(),触发宿主重新渲染,因此value可以在宿主的更新周期中被render()或updated()直接消费——这就是"变化被纳入 Lit 响应式更新"的含义。PerformanceController还额外提供flush()方法,用于立即取出待处理的 performance 记录。
验证结果
仓库的测试(如 mutation-controller_test.ts)展示了核对方式:把组件实例插入 DOM 后await el.updateComplete,在updated()中读取this.observer.value并断言。对应的最小验证路径:
const el = new MyElement(); container.appendChild(el); await el.updateComplete; // 默认会先报告一次初始"变化",此时 value 已被 callback 写入 console.log(el._observer.value); el.resetObserverValue(); el.setAttribute('hi', 'hi'); // 触发一次 mutation await el.updateComplete; // 变化经 requestUpdate 触发渲染后再次读取 console.log(el._observer.value);README 示例中的判断方式:当this._observer.value为真值时渲染出Attributes set!,说明一次属性变化已被观察到并进入了更新循环。若浏览器不支持对应的平台 Observer,控制器会在控制台输出警告,例如MutationController error: browser does not support MutationObserver.、ResizeController error: browser does not support ResizeObserver.,此时控制器不会观察任何内容。
限制与边界
- 该包属于 Lit Labs,官方明确说明它可能收到破坏性变更或停止支持,在生产环境使用前应阅读 Lit Labs 文档(见 packages/labs/observers/README.md 顶部的 WARNING)。
- 服务端环境(SSR)下,构造函数检测到
isServer会提前返回:不创建 observer、不注册控制器,因此这些控制器只在浏览器端生效。 skipInitial的默认行为对 IntersectionController 略有不同:平台 IntersectionObserver 在observe()时就会报告初始交叉状态,控制器用内部标记在skipInitial: true时跳过该状态,其他控制器则是"观察时调用一次空变化回调"。
可继续深入的文件:README(完整 API 说明)、index.ts 与各控制器源码、以及 reactive-controller.ts 中ReactiveController生命周期钩子的定义。
【免费下载链接】litLit is a simple library for building fast, lightweight web components.项目地址: https://gitcode.com/GitHub_Trending/li/lit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考