你正在查看 Lit 的旧版本文档。点击 这里查看最新版本。

装饰器

装饰器是可以修改类、类方法和类字段行为的特殊函数。Lit 使用装饰器为注册元素、响应式属性和查询等提供声明式 API。

装饰器是一个第 3 阶段提案,将被添加到 ECMAScript 标准中。目前没有浏览器实现装饰器,但 BabelTypeScript 等编译器提供了对早期版本装饰器提案的支持。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 装饰器声明一个响应式属性。

有关配置属性的更多信息,请参阅响应式属性

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

你可以通过 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';

要使用装饰器,你需要使用 TypeScriptBabel 等编译器来构建代码。

将来当装饰器成为原生 Web 平台特性时,这可能不再必要。

要与 TypeScript 一起使用装饰器,启用 experimentalDecorators 编译器选项。

你还应确保 useDefineForClassFields 设置为 false。注意,这仅在 target 设置为 esnext 或更高版本时才需要,但建议显式确保此设置为 false

"experimentalDecorators": true,
"useDefineForClassFields": false,

不需要也不建议启用 emitDecoratorMetadata

如果你使用 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 的转译器设置,如上文 TypeScriptBabel 部分所示。