裝飾器
裝飾器是可以用於宣告式註解和修改類別行為的函式。
Lit 提供了一組可選的裝飾器,可為註冊元素、定義響應式屬性和查詢屬性,或將事件選項新增至事件處理方法等事項啟用宣告式 API。
例如,@customElement
和 @property()
裝飾器可讓您以簡潔的宣告方式註冊自訂元素並定義響應式屬性
@customElement('my-element')
export class MyElement extends LitElement {
@property()
greeting = 'Welcome';
}
Lit 支援兩種不同版本的 JavaScript 裝飾器提案 – TypeScript 支援的早期版本(我們稱之為實驗性裝飾器)和我們稱之為標準裝飾器的新最終版本。
這兩個提案之間在使用上有一些細微的差異(標準裝飾器通常需要 accessor
關鍵字)。我們的程式碼範例是針對實驗性裝飾器編寫的,因為我們目前建議將其用於生產環境。
如需更多詳細資訊,請參閱裝飾器版本。
內建裝飾器
“內建裝飾器”的永久連結裝飾器 | 摘要 | 更多資訊 |
---|---|---|
@customElement | 定義自訂元素。 | 定義 |
@eventOptions | 新增事件監聽器選項。 | 事件 |
@property | 定義公用屬性。 | 屬性 |
@state | 定義私有狀態屬性 | 屬性 |
@query | 定義一個屬性,該屬性會傳回元件範本中的元素。 | 陰影 DOM |
@queryAll | 定義一個屬性,該屬性會傳回元件範本中的元素清單。 | 陰影 DOM |
@queryAsync | 定義一個屬性,該屬性會傳回 Promise,該 Promise 會解析為元件範本中的元素。 | 陰影 DOM |
@queryAssignedElements | 定義一個屬性,該屬性會傳回指派給特定插槽的子元素。 | 陰影 DOM |
@queryAssignedNodes | 定義一個屬性,該屬性會傳回指派給特定插槽的子節點。 | 陰影 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';
啟用裝飾器
“啟用裝飾器”的永久連結若要使用裝飾器,您需要使用諸如 TypeScript 或 Babel 等編譯器來建置程式碼。
未來當瀏覽器原生支援裝飾器時,就不再需要這樣做了
搭配 TypeScript 使用裝飾器
“搭配 TypeScript 使用裝飾器”的永久連結TypeScript 支援實驗性裝飾器和標準裝飾器。我們建議 TypeScript 開發人員目前使用實驗性裝飾器,以便獲得最佳編譯器輸出。如果您的專案需要使用標準裝飾器或設定 "useDefineForClassFields": true
,請跳到移轉至標準裝飾器。
若要使用實驗性裝飾器,您必須啟用 experimentalDecorators
編譯器選項。
您也應該確保 useDefineForClassFields
設定為 false
。只有在 target
設定為 ES2022
或更高版本時才需要這樣做,但建議明確地將其設定為 false
。這對於避免宣告屬性時發生類別欄位問題是必要的。
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
}
}
啟用 emitDecoratorMetadata
並非必要,也不建議啟用。
將 TypeScript 實驗性裝飾器移轉至標準裝飾器
“將 TypeScript 實驗性裝飾器移轉至標準裝飾器”的永久連結Lit 裝飾器旨在支援使用 TypeScript 實驗性裝飾器模式的標準裝飾器語法(在類別欄位裝飾器上使用 accessor
)。
這允許從在裝飾屬性中新增 accessor
關鍵字開始,逐步移轉到實驗性裝飾器,而不會變更行為。一旦所有裝飾類別欄位都使用 accessor
關鍵字,您就可以變更編譯器選項以完成移轉至標準裝飾器
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": false, // default for TypeScript 5.0 and up
"useDefineForClassFields": true, // default when "target" is "ES2022" or higher
}
}
注意:accessor
關鍵字是在 TypeScript 4.9 中引入的,而具有中繼資料的標準裝飾器則需要 TypeScript ≥5.2。
搭配 Babel 使用裝飾器
“搭配 Babel 使用裝飾器”的永久連結Babel 從 7.23 版開始支援搭配 @babel/plugin-proposal-decorators
外掛程式的標準裝飾器。Babel 不支援 TypeScript 實驗性裝飾器,因此您必須在裝飾類別欄位中使用 accessor
關鍵字搭配 標準裝飾器語法來使用 Lit 裝飾器。
透過新增 @babel/plugin-proposal-decorators
和這些 Babel 設定來啟用裝飾器
// babel.config.json
{
"plugins": [
["@babel/plugin-proposal-decorators", {"version": "2023-05"}]
]
}
注意:Lit 裝飾器僅適用於 "version": "2023-05"
。不支援其他版本,包括先前支援的 "2018-09"
。
裝飾器版本
“裝飾器版本”的永久連結裝飾器是要加入 ECMAScript 標準的第 3 階段提案。諸如 Babel 和 TypeScript 等編譯器支援裝飾器,但目前沒有瀏覽器實作它們。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
關鍵字來宣告「自動存取子」
class MyClass {
accessor foo = 42;
}
自動存取器會建立一對 getter 和 setter,用於讀取和寫入私有欄位。裝飾器接著可以包裝這些 getter 和 setter。
針對具有實驗性裝飾器的類別欄位(例如 @property()
、@state()
、@query()
等)運作的 Lit 裝飾器,必須使用標準裝飾器應用於存取器或自動存取器。
@customElement('my-element')
export class MyElement extends LitElement {
@property()
accessor greeting = 'Welcome';
}
編譯器輸出考量
“編譯器輸出考量” 的永久連結由於需要產生存取器、私有儲存空間,以及作為裝飾器 API 一部分的其他物件,因此標準裝飾器的編譯器輸出大小相當可觀。
因此,我們建議希望使用裝飾器的使用者,如果可能的話,目前先使用 TypeScript 的實驗性裝飾器。
未來,Lit 團隊計畫在我們可選的 Lit 編譯器中加入裝飾器轉換,以便將標準裝飾器編譯為更精簡的編譯器輸出。原生瀏覽器支援也將完全消除任何編譯器轉換的需求。