iT邦幫忙

2025 iThome 鐵人賽

DAY 10
2

進入第二個元件前,我們先介紹一下 Web Component 的第四個隱藏概念,也就是 slot(插槽)

什麼是 slot ?

不管是使用原生 JS 還是框架,當我們設計一個自訂元件時,通常不希望內容被固定死(設計套件也一樣),而是希望使用的人可以有彈性的應用。

slot 是 Web Component 提供的一種 插槽機制,允許使用者在元件內部插入自訂內容。

如果把 template 想成元件的範本結構,slot 就像是預留的空位,讓使用者可以填入自己想要的內容,但不影響整體元件的封裝(給外部一個有限制但可自訂的入口)。

如果要用框架來說明,那麼在 Angular 就像 <ng-content>, Vue 一樣是 slot,React 則像是 props.children

slot 有什麼好處呢?

  • 更彈性的內容調整及置換:元件可以定義預設的內容,但也可以讓使用者自定內容,slot 提供了開口讓外部自行定義。
  • 結構與樣式分離:開發者設計的元件可以專注在樣式、互動,而使用者則能專注在內容(slot 不會破壞原本的結構)。
  • 可維護性高:同一個元件可以搭配不同的 slot 內容,避免重複開發。

基本使用

不具名 slot

  • 可定義預設內容:當你在使用 slot 時,可以先預設內容結構。假設使用者沒有傳入自定內容,則會使用你預設的內容。
  • 可提供使用者自定內容:使用者自定義內容會被映射到元件內的 slot 位置。

slot

具名 Slot

  • 可以在同一個元件裡放多個 slot,並且用 name 來區分。

slot02

與 template 一起使用

在前面三大核心中有提到 template 可以用來定義一個可複製的 HTML 結構。
而當 slot 與 template 搭配時,我們就能設計一個可重複使用可插入不同內容 的元件!

小練習

今天先做一個小小的練習,試著用之前的 spinner 元件加入 slot 看看!

定義兩個 slot 區塊:

  1. icon : 可以讓使用者插入自訂的 loading 圖示。
  2. label : 可以讓使用者顯示不同的提示文字(例如:Loading...、處理中...)。

我們先在 label slot 先定義一個預設的內容:<span>Loading...</span>

spinner.js

class CatSpinner extends HTMLElement {
  constructor() {
    // JS 繼承機制
    super();

    const shadowRoot = this.attachShadow({ mode: 'open' }); // 加入 shadow DOM
    const cloneNode = this.renderTemplate().content.cloneNode(true); // 複製 template.content
    shadowRoot.appendChild(cloneNode); // 寫入 template
  }

  renderTemplate (){
    const spinnerTemplate = document.createElement('template');

    spinnerTemplate.innerHTML = `
      <style>
        .spinner-container {
          display: flex;
          align-items: center;
          gap: 8px;
        }

        .spinner {
          width: 24px;
          height: 24px;
          border: 3px solid #e5e5e5;
          border-top-color: #4a32e3;
          border-radius: 50%;
          animation: spin 1s linear infinite;
        }

        @keyframes spin {
          to { 
            transform: rotate(360deg); 
          }
        }
      </style>

      <div class="spinner-container">
        <!-- 預設的 spinner icon -->
        <slot name="icon">
          <div class="spinner"></div>
        </slot>

        <!-- 預設的 label -->
        <slot name="label">
          <span>Loading...</span>
        </slot>
      </div>
    `;

    return spinnerTemplate;
  }
}

customElements.define('cat-spinner', CatSpinner);

將加入 slot 加入 html 中:

  1. 試試看,都不傳入 slot 會得到什麼?
  2. 在自訂元件中都傳入自定義的 slot 內容。
<body>
  <div style="display: flex; align-items: center; padding: 20px">
    <h2>Web Component</h2>
    
    <!-- 預設 -->
    <cat-spinner></cat-spinner>

    <!-- 自訂 label -->
    <cat-spinner>
      <span slot="label">處理中,請稍候...</span>
    </cat-spinner>

    <!-- 自訂 icon + label -->
    <cat-spinner>
      <span slot="icon">🐱</span>
      <span slot="label">Uploading...</span>
    </cat-spinner>
  </div>
</body>

依照上方程式碼,透過元件提供的 slot 區域,你可以傳入自定義的內容。

slot-demo

使用 Slot 的一些注意事項

  1. slot 過於自由可能破壞元件的一致性:傳入的內容不符合設計者本預期內容,也許就會與當初設計的預期呈現樣式不同。
  2. 可預期性低:如果 slot 允許傳入任何東西,開發者就很難保證元件的使用方式、呈現出的樣式

在使用 slot 時,盡量使用具名的 slot,使用者就算亂寫內容,也只能丟進指定的 slot 中,且會被預設樣式規範住。


上一篇
DAY 9: Web Component 的屬性 Properties 與 Getter & Setter
下一篇
Day 11: Web Component 應用-Modal 與 slot
系列文
原生元件養成計畫:Web Component12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言