装饰器

装饰器是函数,可用于声明式地注释和修改类的行为。

Lit 提供了一组可选装饰器,这些装饰器支持声明式 API,用于注册元素、定义响应式属性和查询属性,或向事件处理程序方法添加事件选项。

例如,@customElement@property() 装饰器允许您以紧凑、声明式的方式注册自定义元素并定义响应式属性

Lit 支持 JavaScript 装饰器提案的两个不同版本 - TypeScript 支持的早期版本,我们称之为实验性装饰器,以及一个新的最终版本,我们称之为标准装饰器

这两个提案在使用上有一些细微的差别(标准装饰器通常需要accessor关键字)。我们的代码示例是针对实验性装饰器编写的,因为我们目前建议在生产中使用它们。

有关更多详细信息,请参阅装饰器版本

装饰器摘要更多信息
@customElement定义自定义元素。定义
@eventOptions添加事件监听器选项。事件
@property定义公共属性。属性
@state定义私有状态属性属性
@query定义一个返回组件模板中元素的属性。Shadow DOM
@queryAll定义一个返回组件模板中元素列表的属性。Shadow DOM
@queryAsync定义一个返回 Promise 的属性,该 Promise 解析为组件模板中的元素。Shadow DOM
@queryAssignedElements定义一个返回分配给特定插槽的子元素的属性。Shadow DOM
@queryAssignedNodes定义一个返回分配给特定插槽的子节点的属性。Shadow DOM

您可以通过lit/decorators.js模块导入所有 Lit 装饰器

为了减少运行组件所需的代码量,可以将装饰器单独导入组件代码中。所有装饰器都可以在lit/decorators/<decorator-name>.js中找到。例如,

要使用装饰器,您需要使用编译器(如TypeScriptBabel)构建您的代码。

将来,当浏览器原生支持装饰器时,这将不再需要。

TypeScript 支持实验性装饰器和标准装饰器。我们建议 TypeScript 开发人员现在使用实验性装饰器,以获得最佳编译器输出。如果您的项目需要使用标准装饰器或设置"useDefineForClassFields": true,请跳到迁移到标准装饰器

要使用实验性装饰器,您必须启用experimentalDecorators编译器选项。

您还应该确保useDefineForClassFields设置值为false。这仅在target设置为ES2022或更高版本时才需要,但建议将其显式设置为false。这是为了避免在声明属性时出现与类字段相关的问题

启用emitDecoratorMetadata不是必需的,也不建议这样做。

Lit 装饰器旨在支持标准装饰器语法(在类字段装饰器上使用accessor)以及 TypeScript 的实验性装饰器模式。

这允许从添加accessor关键字到装饰属性开始,逐步迁移出实验性装饰器,而不会改变行为。一旦所有装饰的类字段都使用accessor关键字,您就可以更改编译器选项以完成迁移到标准装饰器

注意:accessor关键字是在 TypeScript 4.9 中引入的,带有元数据的标准装饰器需要 TypeScript ≥5.2。

Babel从 7.23 版本开始使用@babel/plugin-proposal-decorators插件支持标准装饰器。Babel 不支持 TypeScript 实验性装饰器,因此您必须使用 Lit 装饰器和标准装饰器语法,在装饰的类字段上使用accessor关键字。

通过添加@babel/plugin-proposal-decorators以及这些 Babel 配置设置,来启用装饰器

注意:Lit 装饰器仅与"version": "2023-05"一起使用。其他版本,包括以前支持的"2018-09",都不支持。

装饰器是第 3 阶段提案,用于添加到 ECMAScript 标准。编译器(如BabelTypeScript)支持装饰器,但浏览器尚未实现它们。Lit 装饰器与 Babel 和 TypeScript 兼容,并且在浏览器原生实现它们后也将兼容。

第 3 阶段意味着什么?

这意味着规范文本已经完成,并且已准备好供浏览器实现。一旦规范在多个浏览器中实现,它就可以进入最终阶段,即第 4 阶段,并被添加到 ECMAScript 标准中。第 3 阶段提案只会因为在实现过程中发现了严重问题而改变。

在 TC39 提案达到第 3 阶段之前,编译器实现了装饰器规范的早期版本。

其中最重要的是TypeScript 的实验性装饰器,Lit 从一开始就支持它,也是我们目前建议使用的。

Babel 随着时间的推移也支持规范的不同版本,从装饰器插件的"version"选项可以看出。过去,Lit 2 支持 Babel 用户的"2018-09"版本,但现在已被放弃,转而支持下面描述的标准"2023-05"版本。

标准装饰器是装饰器的版本,它已在定义 ECMAScript/JavaScript 的 TC39 组织中达成第 3 阶段共识。

标准装饰器在 TypeScript 和 Babel 中受支持,浏览器将在不久的将来提供原生支持。

标准装饰器与实验性装饰器之间最大的区别在于,出于性能原因,标准装饰器不能更改被装饰和替换的类成员的类型 - 字段、访问器和方法 - 并且只会生成相同的类型成员。

由于许多 Lit 装饰器生成访问器,这意味着装饰器需要应用于访问器,而不是类字段。

为了方便起见,标准装饰器规范添加了accessor关键字来声明“自动访问器”。

自动访问器会创建一个 getter 和 setter 对,它们从私有字段读取和写入。装饰器可以包装这些 getter 和 setter。

Lit 装饰器(使用实验性装饰器在类字段上工作 - 例如@property()@state()@query() 等)必须使用标准装饰器应用于访问器或自动访问器

标准装饰器的编译器输出不幸的是非常庞大,因为需要生成访问器、私有存储以及装饰器 API 的其他对象。

因此,我们建议希望使用装饰器的用户,如果可能的话,现在使用 TypeScript 实验性装饰器。

将来,Lit 团队计划将装饰器转换添加到我们的可选 Lit 编译器中,以便将标准装饰器编译成更紧凑的编译器输出。浏览器原生支持也将完全消除对任何编译器转换的需求。