iT邦幫忙

2025 iThome 鐵人賽

DAY 27
3
Modern Web

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

Day 27: Web Component 的框架 Lit - @customElement

  • 分享至 

  • xImage
  •  

花了三天時間,一起初淺的學習了如何將 Web Component 使用在前端的三大框架中。
今天我們再一起將主角拉回建立 Web Component 的軌道上。

前端開發上有許許多多的框架,而建立 Web Component 其實也有一套框架(這時是不是想說那句經典台詞:老子學不動了啊~~~)。
別擔心,相信學會各大框架的你,這一定是輕而易舉,舉一就能反三的框架。

那麼今天要介紹關於開發 Web Component 的框架就是 Lit

Lit 是什麼?

Lit is a simple library for building fast, lightweight web components.

At Lit's core is a boilerplate-killing component base class that provides reactive state, scoped styles, and a declarative template system that's tiny, fast and expressive.
-- from lit.dev

Lit 是由 Google 開發用來建立 Web Components 的輕量級框架。是基於原生的 Web Component 標準(Custom Elements + Shadow DOM + Template literals)的一層封裝。

使用 Lit 開發的元件其實都是標準的 Web Component。從我們這系列文章最初的介紹,到前三篇的解說之下,你應該可以了解到 Web Component 是具有非常好的互通性。
因為瀏覽器原生支持,所以 Web Component 可以用在任何 HTML 的環境中,可以跟任何框架配合使用,也可以不需要框架。

為什麼要使用 Lit ?

就跟我們平時在開發網頁一樣,其實也是為了讓開發更有效率,降低程式碼的複雜度,能用更簡潔的語法來開發 Web Component(前面寫得那麼多篇文章,相信你可能也被複雜大量的程式碼給嚇到了)。

  1. 加入反應式屬性 Reactive Properties。
    Lit 讓我們可以很簡單的把元件的屬性與畫面綁定在一起,當屬性改變時,自動重新渲染畫面。
  2. 模板語法簡潔、事件綁定方便。
  3. 提供額外的生命週期方法,方便在元件第一次渲染完成後做初始化。

Lit 該如何使用

初步定義元件的方法

  1. 元件的繼承:
    是否還記得我們在一開始有 extends HTMLElement 來繼承 HTMLElement 的屬性及方法?
    在使用 Lit 時,我們需要繼承 LitElement
    LitElement 繼承了所有標準 HTMLElement 屬性和方法,並且繼承了自己提供的 ReactiveElement,讓元件可以有屬性到畫面的反應更新。
export class CounterBtn extends LitElement {}
  1. 元件的定義:
    在原生與 Lit 可以使用同一種方式來定義自訂元件 customElements.define()
    但是 Lit 多了一種定義方式,也就是可以使用裝飾器 @customElement 直接定義元件。
  • 原生寫法:
export class CounterBtn extends HTMLElement { // 略... }
customElements.define('counter-btn', CounterBtn);
  • 使用 Lit 裝飾器定義元件-@customElement

注意: @customElement 是裝飾器語法,需要經過編譯,像是 TypeScriptBabel 才能運行。

@customElement('counter-btn')
export class CounterBtn extends LitElement {  // 略... }
  1. 元件的 Shadow DOM:
    由於我們已經繼承了 LitElement 所以不需要再像原生的寫法一樣使用 shadowRoot = this.attachShadow({ mode: 'open' }),Lit 會自動啟用 Shadow DOM。

  2. 模板的寫入:
    你是否還記得,之前都是使用 const template = document.createElement('template') 之後寫入 innerHTML
    而在 Lit 中,你會需要建立一個 render() 的方法,並使用 html 寫入 template。

  • 原生寫法:
render() {
  const template = document.createElement('template');
  template.innerHTML = `<p>Hello Custom Element</p>`;
}
  • Lit 寫法:
render(){
  return html`<p>Hello Custom Element</p>`;
}
  1. 樣式的寫入:
    在這系列的示範中,全部的樣式都是寫在 template.innerHTML 中,而 Lit 提供了 static styles = css 方法,定義在 class 中寫入樣式。
static styles = css`
  button {
    padding: 0.5rem;
    border-bottom: 1px solid #ccc;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
`;

使用 Lit 初步建立一個元件吧

在這篇文章,我希望實作一個 counter 的元件作為範例。

  • 首先使用 vite 建立一個前端專案,選擇 TypeScript
npm create vite@latest lit-demo
  • 安裝 Lit 套件
npm install lit
  • tsconfig.json 加上規則,讓我們可以使用 lit 裝飾器
"compilerOptions": {
  //...略
  "experimentalDecorators": true,
}
  • src/counter.ts 中引入 Lit 相關方法及屬性
import { LitElement, html, css } from 'lit';
import { customElement } from 'lit/decorators.js';
  • 定義自訂元件並加入結構與樣式
@customElement('counter-btn')
export class CounterBtn extends LitElement {
  // 定義樣式
  static styles = css`
    .counter-wrapper {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 16px;
      padding: 32px;
    }
    
    .counter {
      display: flex;
      align-items: center;
      gap: 8px;
    }

    button {
      padding: 0.5rem 1rem;
      font-size: 1rem;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }

    button.increment {
      background-color: #e1d9d9;
    }

    button.decrement {
      background-color: #c9b7b7;
    }

    button.reset {
      background-color: #0d2b44;
      color: white;
    }
  `

  // 寫入模板相關內容
  render() {
    return html`
      <div class="counter-wrapper">
        <div class="counter">
          <button class="decrement">-</button>
          <span>Count:</span>
          <button class="increment">+</button>
        </div>
        <button class="reset">Reset</button>
      </div>
    `
  }
}
  • main.ts 中引入元件
import './counter.ts'

const app = document.querySelector('#app')!;

// 建立一個 counter 元件
const counter = document.createElement('counter-btn');

app.appendChild(counter);
  • index.html 中引入 main.ts
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>
  • npm run dev 跑起來看看元件是否有出現
    lit-demo

恭喜!使用 Lit 初步建立的元件就定義好囉~
那麼明天,我們再來說說關於屬性還有事件的傳遞吧 d(`・∀・)b !


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

尚未有邦友留言

立即登入留言