裝飾器

裝飾器是可以用於宣告式註解和修改類別行為的函式。

Lit 提供了一組可選的裝飾器,可為註冊元素、定義響應式屬性和查詢屬性,或將事件選項新增至事件處理方法等事項啟用宣告式 API。

例如,@customElement@property() 裝飾器可讓您以簡潔的宣告方式註冊自訂元素並定義響應式屬性

Lit 支援兩種不同版本的 JavaScript 裝飾器提案 – TypeScript 支援的早期版本(我們稱之為實驗性裝飾器)和我們稱之為標準裝飾器的新最終版本。

這兩個提案之間在使用上有一些細微的差異(標準裝飾器通常需要 accessor 關鍵字)。我們的程式碼範例是針對實驗性裝飾器編寫的,因為我們目前建議將其用於生產環境。

如需更多詳細資訊,請參閱裝飾器版本

裝飾器摘要更多資訊
@customElement定義自訂元素。定義
@eventOptions新增事件監聽器選項。事件
@property定義公用屬性。屬性
@state定義私有狀態屬性屬性
@query定義一個屬性,該屬性會傳回元件範本中的元素。陰影 DOM
@queryAll定義一個屬性,該屬性會傳回元件範本中的元素清單。陰影 DOM
@queryAsync定義一個屬性,該屬性會傳回 Promise,該 Promise 會解析為元件範本中的元素。陰影 DOM
@queryAssignedElements定義一個屬性,該屬性會傳回指派給特定插槽的子元素。陰影 DOM
@queryAssignedNodes定義一個屬性,該屬性會傳回指派給特定插槽的子節點。陰影 DOM

您可以透過 lit/decorators.js 模組匯入所有 Lit 裝飾器

若要減少執行元件所需的程式碼量,可以將裝飾器個別匯入元件程式碼。所有裝飾器都可在 lit/decorators/<decorator-name>.js 中取得。例如,

若要使用裝飾器,您需要使用諸如 TypeScriptBabel 等編譯器來建置程式碼。

未來當瀏覽器原生支援裝飾器時,就不再需要這樣做了

TypeScript 支援實驗性裝飾器和標準裝飾器。我們建議 TypeScript 開發人員目前使用實驗性裝飾器,以便獲得最佳編譯器輸出。如果您的專案需要使用標準裝飾器或設定 "useDefineForClassFields": true,請跳到移轉至標準裝飾器

若要使用實驗性裝飾器,您必須啟用 experimentalDecorators 編譯器選項。

您也應該確保 useDefineForClassFields 設定為 false。只有在 target 設定為 ES2022 或更高版本時才需要這樣做,但建議明確地將其設定為 false。這對於避免宣告屬性時發生類別欄位問題是必要的。

啟用 emitDecoratorMetadata 並非必要,也不建議啟用。

將 TypeScript 實驗性裝飾器移轉至標準裝飾器

“將 TypeScript 實驗性裝飾器移轉至標準裝飾器”的永久連結

Lit 裝飾器旨在支援使用 TypeScript 實驗性裝飾器模式的標準裝飾器語法(在類別欄位裝飾器上使用 accessor)。

這允許從在裝飾屬性中新增 accessor 關鍵字開始,逐步移轉到實驗性裝飾器,而不會變更行為。一旦所有裝飾類別欄位都使用 accessor 關鍵字,您就可以變更編譯器選項以完成移轉至標準裝飾器

注意:accessor 關鍵字是在 TypeScript 4.9 中引入的,而具有中繼資料的標準裝飾器則需要 TypeScript ≥5.2。

Babel 從 7.23 版開始支援搭配 @babel/plugin-proposal-decorators 外掛程式的標準裝飾器。Babel 不支援 TypeScript 實驗性裝飾器,因此您必須在裝飾類別欄位中使用 accessor 關鍵字搭配 標準裝飾器語法來使用 Lit 裝飾器。

透過新增 @babel/plugin-proposal-decorators 和這些 Babel 設定來啟用裝飾器

注意:Lit 裝飾器僅適用於 "version": "2023-05"。不支援其他版本,包括先前支援的 "2018-09"

裝飾器是要加入 ECMAScript 標準的第 3 階段提案。諸如 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。

針對具有實驗性裝飾器的類別欄位(例如 @property()@state()@query() 等)運作的 Lit 裝飾器,必須使用標準裝飾器應用於存取器或自動存取器。

由於需要產生存取器、私有儲存空間,以及作為裝飾器 API 一部分的其他物件,因此標準裝飾器的編譯器輸出大小相當可觀。

因此,我們建議希望使用裝飾器的使用者,如果可能的話,目前先使用 TypeScript 的實驗性裝飾器。

未來,Lit 團隊計畫在我們可選的 Lit 編譯器中加入裝飾器轉換,以便將標準裝飾器編譯為更精簡的編譯器輸出。原生瀏覽器支援也將完全消除任何編譯器轉換的需求。