[譯] 編寫能夠複用的 HTML 模板

在咱們的上一篇文章中, 咱們討論了 web 組件規範(自定義元素、shadow DOM 和 HTML 模板)的高級特性。在本文以及接下來的三篇文章中,咱們將這些技術應用到測試並更詳細地去驗證它們,看下咱們在現在的產品如何應用它們。爲了作到這些,咱們將會從零開始構建一個自定義模式的對話框,來查看這些不一樣的技術如何組裝在一塊兒。css

系列文章:

  1. Web 組件簡介
  2. 編寫能夠複用的 HTML 模板 (本文)
  3. 從 0 開始建立自定義元素
  4. 使用 Shadow DOM 封裝樣式和結構
  5. Web 組件的高階工具

HTML 模板

Web 組件規範中最不被承認可是最強大的功能之一是 <模板> 元素。在這個系列的第一篇文章中,咱們將這種模板元素定義爲『僅在調用時才渲染的用戶自定義 HTML 模板』。換句話說,模板就是一種當瀏覽器被告知時才執行的 HTML 代碼,其餘狀況下是被忽略的。html

這種模塊能夠經過許多有趣的方式去傳遞和應用。基於本文的目的,咱們將看下如何爲一種最終應用到自定義元素中的對話框建立模板。前端

定義你的模板

就像它聽起來這樣簡單,一個 <template> 是一種 HTML 元素,因此一個含內容的模板所具有的最基本形式以下:node

<template>
  <h1>Hello world</h1>
</template>
複製代碼

在瀏覽器中運行這段代碼會顯示空白頁面,由於瀏覽器並無渲染模板元素內容。這種方式的強大之處在於它容許咱們保存自定義內容(或內容結構),以供後續使用,而不須要使用 JavaScript 來動態編寫 HTML 代碼。android

爲了使用模板,咱們 須要用到 JavaScript。ios

const template = document.querySelector('template');
const node = document.importNode(template.content, true);
document.body.appendChild(node);
複製代碼

真正神奇的地方在於 document.importNode 方法。這個函數將會爲模板的 內容 建立一份副本,而且作好將拷貝插入其餘文檔(或文檔片斷)的準備。函數的第一個參數獲取到模板的內容,第二個參數告訴瀏覽器要對元素的 DOM 子樹作一份深度拷貝(也就是拷貝它的全部子節點)。git

咱們能夠直接使用 template.content,可是這樣作的話,咱們隨後須要把內容從元素中移除並將它拼接到其餘文檔的 body 部分。任何 DOM 節點僅能夠被接入到一個位置,因此隨後對模板內容的使用將會致使空文檔片斷(基本上是一個空值),由於以前已移動了內容對象。使用 document.importNode 容許咱們在不一樣的位置來複用同一個模板內容的實例。github

以上代碼執行後,節點內容會被拼接到 document.body 對象,並被渲染顯示給用戶。這樣最終使咱們可以作許多有趣的事情,好比爲咱們的用戶(或者咱們程序的消費者)提供建立內容的模板,相似下面的 demo,在第一篇文章咱們討論過:web

請參閱筆記模板樣例,來自 CodePen 的 Caleb Williams (@calebdwilliams)。後端

這個例子中,咱們提供了兩個模板來渲染一樣的內容 —— 做者和他寫的書。當表格變化時,咱們選擇渲染與該變化值相關聯的模板。使用相同的技術容許咱們最終建立一個自定義元素,該元素將使用稍後定義的模板。

模板的多功能性

模板中一個有趣的點是咱們能夠包含 任意 HTML,包括腳本和樣式元素。一個很是簡單的模板例子是添加一個能夠提示被點擊的按鈕。

<button id="click-me">Log click event</button>
複製代碼

讓咱們加點樣式:

button {
  all: unset;
  background: tomato;
  border: 0;
  border-radius: 4px;
  color: white;
  font-family: Helvetica;
  font-size: 1.5rem;
  padding: .5rem 1rem;
}
複製代碼

...而後經過一個很是簡單的腳原本調用按鈕:

const button = document.getElementById('click-me');
button.addEventListener('click', event => alert(event));
複製代碼

固然,咱們能夠直接使用 <style></script> 標籤來將他們放在同一個文件中,而非放在分離的文件中:

<template id="template">
  <script>
    const button = document.getElementById('click-me');
    button.addEventListener('click', event => alert(event));
  </script>
  <style>
    #click-me {
      all: unset;
      background: tomato;
      border: 0;
      border-radius: 4px;
      color: white;
      font-family: Helvetica;
      font-size: 1.5rem;
      padding: .5rem 1rem;
    }
  </style>
  <button id="click-me">Log click event</button>
</template>
複製代碼

一旦這個元素被加入到 DOM 結構中,咱們會看到一個 ID 爲 #click-me 的新按鈕,一個全局的 CSS selector 被綁定到這個按鈕的 ID,一個簡單的事件監聽回調函數會提示元素的點擊事件。

至於咱們的腳本,咱們僅需使用 document.importNode 來拼接內容,而且咱們有一個包含大體內容的 HTML 模板,在頁與頁之間能夠複用。

請參閱筆記包含腳本和樣式的模板例子,來自 CodePen 的 Caleb Williams (@calebdwilliams)。

爲咱們的對話框編寫模板

回到咱們編寫一個對話框元素這個任務,咱們但願定義本身的模板內容和樣式。

<template id="one-dialog">
  <script>
    document.getElementById('launch-dialog').addEventListener('click', () => {
      const wrapper = document.querySelector('.wrapper');
      const closeButton = document.querySelector('button.close');
      const wasFocused = document.activeElement;
      wrapper.classList.add('open');
      closeButton.focus();
      closeButton.addEventListener('click', () => {
        wrapper.classList.remove('open');
        wasFocused.focus();
      });
    });
  </script>
  <style>
    .wrapper {
      opacity: 0;
      transition: visibility 0s, opacity 0.25s ease-in;
    }
    .wrapper:not(.open) {
      visibility: hidden;
    }
    .wrapper.open {
      align-items: center;
      display: flex;
      justify-content: center;
      height: 100vh;
      position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
      opacity: 1;
      visibility: visible;
    }
    .overlay {
      background: rgba(0, 0, 0, 0.8);
      height: 100%;
      position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
      width: 100%;
    }
    .dialog {
      background: #ffffff;
      max-width: 600px;
      padding: 1rem;
      position: fixed;
    }
    button {
      all: unset;
      cursor: pointer;
      font-size: 1.25rem;
      position: absolute;
        top: 1rem;
        right: 1rem;
    }
    button:focus {
      border: 2px solid blue;
    }
  </style>
  <div class="wrapper">
  <div class="overlay"></div>
    <div class="dialog" role="dialog" aria-labelledby="title" aria-describedby="content">
      <button class="close" aria-label="Close">&#x2716;&#xfe0f;</button>
      <h1 id="title">Hello world</h1>
      <div id="content" class="content">
        <p>This is content in the body of our modal</p>
      </div>
    </div>
  </div>
</template>
複製代碼

這段代碼將成爲咱們對話框的基礎部分。簡單介紹一下,咱們有一個全局的關閉按鈕,一個標題和一些內容。咱們也添加了一些行爲來實現可視化觸發對話框(儘管它還沒法被訪問)。不幸的是,樣式和腳本內容並不是僅限做用於咱們的模板,而是應用於整個文件,當咱們將多個模板實例添加到 DOM 時,並無產生理想的中的效果。在下篇文章中,咱們將應用自定義元素f生成方法並建立咱們本身的元素,實時使用該模板並封裝元素的行爲。

請查閱筆記以腳本模板來編寫對話框 ,來自 CodePen 的 Caleb Williams (@calebdwilliams)。

Article Series:

  1. Web Components 簡介
  2. 編寫能夠複用的 HTML 模板 (本文)
  3. 從 0 開始建立自定義元素
  4. 使用 Shadow DOM 封裝樣式和結構
  5. Web 組件的高階工具

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索