装饰器
装饰器是可以修改类、类方法和类字段行为的特殊函数。Lit 使用装饰器为注册元素、响应式属性和查询等提供声明式 API。
装饰器是一个第 3 阶段提案,将被添加到 ECMAScript 标准中。目前没有浏览器实现装饰器,但 Babel 和 TypeScript 等编译器提供了对早期版本装饰器提案的支持。Lit 装饰器可与 Babel 和 TypeScript 一起使用,并将在规范在浏览器中实现后更新以适应最终规范。
详见启用装饰器部分。
第 3 阶段意味着什么?
第 3 阶段意味着规范文本已经完成,准备好供浏览器实现。一旦规范在多个浏览器中实现,它可以进入最后阶段——第 4 阶段,并被添加到 ECMAScript 标准中。第 3 阶段提案仍然可能发生变化,但只有在实现过程中发现严重问题时才会改变。
Lit 提供了一组装饰器,可减少定义组件时需要编写的样板代码量。例如,@customElement 和 @property 装饰器使基本元素定义更加紧凑:
customElement('my-element')export class MyElement extends LitElement { property() greeting = "Welcome"; property() name = "Sally"; property({type: Boolean}) emphatic = true; //...} @customElement 装饰器定义一个自定义元素,等同于调用:
customElements.define('my-element', MyElement); @property 装饰器声明一个响应式属性。
有关配置属性的更多信息,请参阅响应式属性。
内置装饰器
Permalink to "内置装饰器"| 装饰器 | 摘要 | 更多信息 |
|---|---|---|
@customElement | 定义一个自定义元素 | 上文 |
@eventOptions | 添加事件监听器选项 | 事件 |
@property | 定义一个公共属性 | 属性 |
@state | 定义一个私有状态属性 | 属性 |
@query | 定义一个返回组件模板中元素的属性 | Shadow DOM |
@queryAll | 定义一个返回组件模板中元素列表的属性 | Shadow DOM |
@queryAsync | 定义一个返回 Promise(解析为组件模板中的元素)的属性 | Shadow DOM |
@queryAssignedElements | 定义一个返回分配给特定 slot 的子元素的属性 | Shadow DOM |
@queryAssignedNodes | 定义一个返回分配给特定 slot 的子节点的属性 | Shadow DOM |
导入装饰器
Permalink to "导入装饰器"你可以通过 lit/decorators.js 模块导入所有 Lit 装饰器:
import {customElement, property, eventOptions, query} from 'lit/decorators.js'; 为了减少运行组件所需的代码量,装饰器可以单独导入到组件代码中。所有装饰器都可以在 lit/decorators/<decorator-name>.js 路径下找到。例如,
import {customElement} from 'lit/decorators/custom-element.js';import {eventOptions} from 'lit/decorators/event-options.js'; 启用装饰器
Permalink to "启用装饰器"要使用装饰器,你需要使用 TypeScript 或 Babel 等编译器来构建代码。
将来当装饰器成为原生 Web 平台特性时,这可能不再必要。
在 TypeScript 中使用装饰器
Permalink to "在 TypeScript 中使用装饰器"要与 TypeScript 一起使用装饰器,启用 experimentalDecorators 编译器选项。
你还应确保 useDefineForClassFields 设置为 false。注意,这仅在 target 设置为 esnext 或更高版本时才需要,但建议显式确保此设置为 false。
"experimentalDecorators": true,"useDefineForClassFields": false, 不需要也不建议启用 emitDecoratorMetadata。
在 Babel 中使用装饰器
Permalink to "在 Babel 中使用装饰器"如果你使用 Babel 编译 JavaScript,可以通过添加以下插件和设置来启用装饰器:
注意,对于最新版本的 Babel,可能不需要 @babel/plugin-proposal-class-properties。
要设置插件,请在 Babel 配置中添加类似以下代码:
"assumptions": { "setPublicClassFields": true},"plugins": [ ["@babel/plugin-proposal-decorators", { "version": "2018-09", "decoratorsBeforeExport": true }], ["@babel/plugin-proposal-class-properties"]] Babel 装饰器支持已使用 version: '2018-09' 进行了测试。这目前是默认值,但我们建议显式设置版本以防默认值发生变化。不支持其他版本('2021-12' 或 'legacy'),但随着 Babel 的发展这可能会改变。如果你想尝试,请参阅 Babel 文档。
在 TypeScript 和 Babel 中同时使用装饰器
Permalink to "在 TypeScript 和 Babel 中同时使用装饰器"当 TypeScript 与 Babel 一起使用时,在 Babel 配置中将 TypeScript 转换排在装饰器转换之前很重要,如下所示:
{ "assumptions": { "setPublicClassFields": true }, "plugins": [ ["@babel/plugin-transform-typescript", { "allowDeclareFields": true }], ["@babel/plugin-proposal-decorators", { "version": "2018-09", "decoratorsBeforeExport": true }], ["@babel/plugin-proposal-class-properties"] ]} allowDeclareFields 设置通常不需要,但如果你想在不使用装饰器的情况下定义响应式属性,它会很有用。例如,
static properties = { foo: {} };
declare foo: string;
constructor() { super(); this.foo = 'bar';} 避免类字段和装饰器的问题
Permalink to "避免类字段和装饰器的问题"类字段与声明响应式属性之间存在有问题的交互。详见声明属性时避免类字段的问题。
当前的装饰器第 3 阶段提案没有直接解决此问题,但随着提案的发展和成熟,应该会得到解决。
使用装饰器时,必须正确配置 Babel 和 TypeScript 的转译器设置,如上文 TypeScript 和 Babel 部分所示。