如果各位有在使用Vue,看到這二個HTML Element會有種很熟悉的感覺。你沒看錯,Vue和web component在這裡也有許多共同之處。
提到template and slot就不得不先說明HTML import,這個功能本來也是web component的技術之一。可以先把HTML,css和js寫入一個HTML,再分別載入到主HTML。但因為各種原因,最後本功能取消,現在只能在Vue的單文件模式中看到HTML import的殘影了。
如果有在使用Vue的單文件模式,在一個檔案中用'template'、'style'和'script'三個標籤把HTML,css,js分別包起來就是HTML import的目標
因為HTML import技術消失,template 這個HTML element現在的作用就像是React的React.Fragment,可以一次設定多個節點又不用附加多餘的節點。
HTML
<ul id='ul'></ul>
<template id='li-list'>
<li>111</li>
<li>222</li>
<li>333</li>
<template>
<-- 上下二個會出現一樣的結果 -->
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
Javascript
const templateNode = document.getElementById('li-list')
const liList = templateNode.content.cloneNode(true);
const ulNode = document.getElementById('ul')
ulNode.appendChild(liList)
React 對應的寫法
const Ul = () => (
<ul>
<LiList />
</ul>
)
const LiList = () => (
<>
<li>111</li>
<li>222</li>
<li>333</li>
</>
)
slot 這個HTML element需要使用shadow DOM才能發揮功能,之後的文章會進一步說明。
如果有在使用Vue的話,web component和Vue的slot除了語法不一樣之外,使用起來一模一樣。
HTML的部分
<my-com>
<div slot="slot1">111</div>
<div slot="slot2">222</div>
<div>333</div>
</my-com>
<-- 上面web component的Shadow DOM會形成下面的樣子 -->
<div>
<div>
<div>111</div>
</div>
<div>
<div>333</div>
</div>
<div>
<div>222</div>
</div>
</div>
Javascript的部分
class MyComponent extends HTMLElement {
constructor() {
super();
this.render = this.render.bind(this);
}
connectedCallback() {
// 下面二行的用法之後的文章會解釋
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(this.render())
}
render() {
const template = document.createElement('template');
template.innerHTML = `
<div>
<div>
<slot name="slot1"></slot> // 把子節點中,屬性slot是'slot1'的子節點放入這裡
</div>
<div>
<slot></slot> // 把子節點中,沒有設定屬性slot的子節點放入這裡
</div>
<div>
<slot name="slot2"></slot> // 把子節點中,屬性slot是'slot2'的子節點放入這裡
</div>
</div>
`;
return template.content;
}
}
customElements.define('my-com', MyComponent);