- 原文地址:Crafting Reusable HTML Templates
- 原文做者:Caleb Williams
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:Mirosalva
- 校對者:xionglong58,HearFishle
在咱們的上一篇文章中, 咱們討論了 web 組件規範(自定義元素、shadow DOM 和 HTML 模板)的高級特性。在本文以及接下來的三篇文章中,咱們將這些技術應用到測試並更詳細地去驗證它們,看下咱們在現在的產品如何應用它們。爲了作到這些,咱們將會從零開始構建一個自定義模式的對話框,來查看這些不一樣的技術如何組裝在一塊兒。css
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">✖️</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)。
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。