iT邦幫忙

2025 iThome 鐵人賽

DAY 28
3
Modern Web

原生元件養成計畫:Web Component系列 第 28

Day 28: Web Component 的框架 Lit - @property

  • 分享至 

  • xImage
  •  

昨天我們初步使用 vite + TypeScript + Lit 建立了初步的元件架構。
那麼今天,我們就接續來說說 Lit 的其他方法及功能吧!

Lit 中的 @property


在最初學習 Web Component 時,我們花了兩篇章來詳細說明了 attributeproperty 的用法。

  • attribute 是來自於 html 結構上的字串值屬性。
<custom-input label="text"></custom-input>

並且要透過 observedAttributes 以及 attributeChangedCallback 來監聽屬性變化,在實作表單元件的那幾篇文章中,我想你應該覺得 attributeChangedCallback 變得很長,難以閱讀以及維護。

  • property 則是元素上的屬性,可以接受物件、布林、字串等等各類型的值。
get label() {
  return this._label;
}

set label(value) {
  this._label = value;
}

而 Lit 透過 static properties@property(),讓彼此可以自動同步,不用再手動寫一堆的程式碼。

static properties & @property

可設定的屬性如下:

屬性 說明 非必填 / 預設值
type 將 Attribute 字串解析為指定的類型傳給 Property 非必填,預設為 string
attribute Property 是否與某個 Attribute 關聯 非必填,預設為 true
reflect 是否同步到 Attribute 非必填,預設為 false
hasChanged 用來確定屬性值是否變更的方法 非必填,預設使用 (newValue !== oldValue)
converter 用於在屬性和 Attribute 之間轉換的自訂轉換器 非必填,未指定時使用預設屬性轉換器
noAccessor 設定為 true 以避免產生預設屬性存取器 非必填,預設為 false

其他更詳細的用法及說明請詳見 Lit

使用方法:

  • 有編譯器的狀況下,會使用 @property
    首先為了避免在聲明屬性時類別欄位出現問題,我們需要在 tsconfig.json 加入:
# 保持舊行為,不會破壞 Lit 的 getter/setter 反應性
"useDefineForClassFields": false,

如果沒加入的話,將會得到錯誤:
property-error

使用 @property 加入屬性:

import { property } from 'lit/decorators.js';

@property({ type: String, reflect: true }) name!: string;
@property({ type: Number }) age!: number;

constructor() {
  super();
  this.name = 'Ada';
  this.age = 18;
}
@property({ type: String, reflect: true }) name = 'Ada';
@property({ type: Number }) age = 18;

  • 在沒有編譯器的寫法下,會使用 static properties
static properties = {
  name: { type: String, reflect: true },
  age: { type: Number }
};

constructor() {
  super();
  this.name = 'Ada';
  this.age = 18;
}

試試看:

假設今天這個 counter 需要紀錄 countdisabled 以及 title,並且都要同步到 attribute。

@customElement('counter-btn')
export class CounterBtn extends LitElement {
  @property({ type: Number, reflect: true }) count!: number;
  @property({ type: Boolean, reflect: true, }) disabled!: boolean;
  @property({ type: String,  reflect: true, }) title!: string;
  
  constructor() {
    super();
    this.count = 10;
    this.disabled = false;
    this.title = 'WC-Lit Counter'
  }

  static styles = css` 
    // ...以下略
  `

以上你已經成功的設定好 property 了,但是我們應該怎麼應用到模板上呢?
這時,我們就需要來介紹一些 Lit 的模板表達式 expressions
我們先介紹兩種模板表達式:基本插值 Child nodes & Attributes, 布林屬性 Boolean Attributes

  1. 基本插值 Child nodes & Attributes
    會使用到 ${} 來做字串或變數插值,直接將值放入模板中,像範例中的 ${activeClass}, ${name} 都可以視為一般的變數值插入。
<button class=${activeClass}>Button: ${name}</button>
  1. 布林屬性 Boolean Attributes
    如果要設定布林屬性,需要加入 ?的前綴於屬性名稱前。
    Lit 會依據布林值是 true 或 false 自動加上或移除屬性。
    如果 ?disabled 表達式的結果是 true,則新增 disabled 屬性;如果計算結果是 false,則刪除 disabled 屬性。
    應用場景像是 checked 或是 readonly 等等時機。
<!--  如果 noValue 為真,則加入 disabled,反之則移除   -->
<button ?disabled=${!noValue}>Click me!</button>

接下來,就將上方定義的 property 加入模板中吧!

render() {
  return html`
    <div class="counter-wrapper">
      <h3>${this.title}</h3>
      <div class="counter">
        <button class="decrement">-</button>
        <span>Count: ${this.count}</span>
        <button class="increment">+</button>
      </div>
      <button class="reset" ?disabled=${this.disabled}>
        Reset
      </button>
    </div>
  `;
}

可以發現,我們定義的 title 以及初始 count 的值是從 10 開始,畫面上也有出現了!

property

接下來,先手動將 disabled 改為 true,並為按鈕加上 disabled 的 class,可以看見畫面也改變了。
property02

到這裡,就將 Lit 框架的初步屬性方法與概念都介紹完了。
目前的元件都還是處於靜態的畫面,下一篇,一樣要讓元件可以動起來 (ㄏ ̄▽ ̄)ㄏ ㄟ( ̄▽ ̄ㄟ)!

程式碼請詳見 Github


上一篇
Day 27: Web Component 的框架 Lit - @customElement
系列文
原生元件養成計畫:Web Component28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言