在上一章節中主要介紹了Custom elements(自定義元素),Shadow DOM(影子DOM)的使用,我們發現其實只使用上述的兩種方式,已經可以構建我們平時需要的組件,那麼爲什麼還需要HTML templates(HTML模板)技術呢?
不知道大家還記不記得之前創建元素的方式:
const input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('class', 'input-vlaue');
創建一個input就需要寫這些js代碼,很明顯,如果當html文檔結構太深或者節點過多時,寫出太多的創建html 節點的代碼,還是很頭疼的。一方面代碼量過多且層級結構不清晰,另一方面時css也是用此方式創建,如何使用僞類呢? 多少是方便的。所以便有了HTML templates(HTML模板)技術。
我們先來看下它的定義:
HTML內容模板(<template>)元素是一種用於保存客戶端內容機制,該內容在加載頁面時不會呈現,但隨後可以(原文爲 may be)在運行時使用JavaScript實例化。") 和
<slot>
元素使您可以編寫不在呈現頁面中顯示的標記模板。然後它們可以作爲自定義元素結構的基礎被多次重用。
其實就是它可以讓你在編寫組件時,可以預先定義好模板,然後再在模板上發展出自己的組件。
示例:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./main.js"></script>
</head>
<body>
<template id="my-paragraph">
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p><slot name="my-text">默認文本</slot></p>
</template>
<my-paragraph>
<span slot="my-text">個性化文本</span>
</my-paragraph>
<my-paragraph>
<ul slot="my-text">
<li>列表條目1</li>
<li>列表條目2</li>
</ul>
</my-paragraph>
</body>
</html>
main.js
customElements.define('my-paragraph',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('my-paragraph');
const templateContent = template.content;
this.attachShadow({mode: 'open'}).appendChild(
templateContent.cloneNode(true)
);
}
}
);
定義模板的的代碼:
<template id="my-paragraph">
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p><slot name="my-text">默認文本</slot></p>
</template>
由於這裏的html import已經不被各大瀏覽器支持了,所以這裏的定義模板的模塊只能寫到使用的html文本里面,或者使用js創建,寫入到main.js裏面。如下的例子,將template獨立到js文件中。
示例:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./main.js"></script>
</head>
<body>
<my-paragraph>
<span slot="my-text">個性化文本</span>
</my-paragraph>
<my-paragraph>
<ul slot="my-text">
<li>列表條目1</li>
<li>列表條目2</li>
</ul>
</my-paragraph>
</body>
</html>
main.js
const str = `
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p><slot name="my-text">默認文本</slot></p>
`;
customElements.define('my-paragraph',
class extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({mode: 'open'});
//const template = document.getElementById('my-paragraph');
// const templateContent = template.content;
const template = document.createElement('template');
template.innerHTML = str;
const templateContent = template.content;
shadow.appendChild(
templateContent.cloneNode(true)
);
}
}
);
以上便是對Web Components的一個基本的認識和使用。由此可以看出Web Components在組件化開發方向的優勢,可是在使用過程中也有一定劣勢,以下便是目前自己不太喜歡的地方:
個人不太喜歡的地方
- 無法在組件內部使用公共的樣式,例如引入了外部樣式,即使在組件內部使用該樣式對應的class name也不會起作用,例如下面的代碼,雖然在 slot外部的p標籤內加了class name,但是在組件外部也是無法使用.test{}來定製樣式了,這樣一來就無法使用很多開源的css類庫了。
const str = `
<style>
p {
color: white;
background-color: #909090;
padding: 5px;
border: 1px soli silver;
}
</style>
<p class="test"><slot name="my-text">默認文本</slot></p>
`;
- 沒了html import 語法,template就只能定義顯示的html文件中,顯然這不是我們想要的組件,我們希望的組件是簡潔明瞭,使用簡單,而這看起來組件和html還有了耦合。當然也可以把template寫入到js中,但是如果template結構複雜,就會發現自負串過長,代碼結構不美觀,且html,css,js混合到了一起。
- 其他的,暫時想不起來了...
參考網址:
MSDN:https://developer.mozilla.org/zh-CN/docs/Web/Web_Components
W3C: https://www.w3.org/html/ig/zh/wiki/Web-Components#.E7.AE.80.E4.BB.8B
web componets 實例代碼:https://github.com/mdn/web-components-examples
HTML5 Rocks: https://www.html5rocks.com/en/tutorials/webcomponents/customelements/#instantiating
阮一峯:https://javascript.ruanyifeng.com/htmlapi/webcomponents.html#toc12
知乎:https://zhuanlan.zhihu.com/p/64619005