iT邦幫忙

2025 iThome 鐵人賽

DAY 5
1
Modern Web

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

Day 5: Web Component 中的模板 Template

  • 分享至 

  • xImage
  •  

終於要介紹第三個核心 Template

在前兩篇文章中已經介紹了 Web Component 的 Custom Element 與 Shadow DOM,接下來要介紹是 Template。

你是否還記得之前的範例,直接在 Shadow root 使用 innerHTML 加入內容:

shadowRoot.innerHTML = `... <div class="spinner"></div>`

但是使用這種方式來定義元件內容,可能會有以下問題:

  1. 在程式碼中混雜 HTML,可讀性差。
  2. 難以動態生成或修改 HTML 內容

所以接下來我們需要用更有效率也更好讀的做法: template, 來開發 Web Component。

為什麼需要 Template?

<template>在瀏覽器裡預先解析、但不會渲染的 DOM 樣板,也就是建立一組不呈現到頁面上的 HTML 元素
就如標籤字面上所說的,你可以把它當成元件內部的範本,讓你更方便的複製其中的內容。
如果你有寫過 angular,他其實跟 ng-template 的概念是一樣的。
而 React 沒有 <template> 的概念,因為 JSX 本身就已經是模板函數化。

要怎麼建立 HTML Template ?

可以使用 template 標籤,或是使用 document.createElement('template')

  • 使用 template 標籤
<template>
  <style></style>
  <div class="spinner"></div>
</template>
  • 使用 document.createElement('template')
    我們在這篇文章中會使用這個方式來建立一個 template,template 裡的內容不會直接渲染,所以 <style> 也不會立刻影響頁面(可以做到局部封裝)。

spinner.js
我們建立一個 renderTemplate() 的函式

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

  spinnerTemplate.innerHTML = `
    <style>
	  .spinner {
	    width: 40px;
	    height: 40px;
	    border: 4px solid #e8e5e5;
	    border-top-color: #926dec;
	    border-radius: 50%;
	    animation: spin 1s linear infinite;
	  }
	  @keyframes spin {
	    to { transform: rotate(360deg); }
	  }
    </style>

    <div class="spinner"></div>
  `;	
	
  return spinnerTemplate;	
}

將 Template 呈現在畫面上

  1. 使用 template.content.cloneNode(true),將模板的內容複製出來。

注意:如果只使用 template.cloneNode(true) 是看不到任何東西的,記得要拿 content 內的東西

  • cloneNode(true): 深拷貝(deep clone):會把整棵子樹都複製(包含 <style><button>...)。
  • cloneNode(false): 淺拷貝(shallow clone):只複製最外層的空 fragment(文件片段),沒有子節點,會什麼都看不到。
  1. 將複製出的的節點 append 至已經建立的 DOM 元素,這裡會使用 shadowRoot.appenChild(cloneNode)

spinner.js

class CatSpinner extends HTMLElement {
  constructor() {
    super();

    const shadowRoot = this.attachShadow({ mode: 'open' });
    const cloneNode = this.renderTemplate().content.cloneNode(true);
    shadowRoot.appendChild(cloneNode);
  }
}

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

index.html

<body>
  <div style="display: flex; gap: 12px; padding: 20px">
    <h2>Web Component</h2>
    <cat-spinner></cat-spinner>
  </div>
  <script src="spinner.js"></script>
</body>

這時你會看見剛剛有加入樣式的按鈕就呈現在畫面上了。

template
(成功找到上傳 gif 的方法了~spinner 動起來啦~(ノ>ω<)ノ)

如果你直接 shadow.appendChild(template.content),它會把原本的內容搬走,下次再用就空了。
所以要先複製一份出來再插入,才能多次重用。

  • 你也試試看:如果沒有先複製,像下方的範例程式碼
    for (let i = 0; i < 3; i++) {
      shadowRoot.appendChild(btnTemplate.content);
    }

當你這樣做的時候,會發現畫面上只出現一個元件!


上一篇
Day 4: Web Component 中的影子樹 Shadow DOM
下一篇
Day 6: Web Component 的生命週期 Life cycle
系列文
原生元件養成計畫:Web Component6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言