🔸<template>
browser ⟩ web components ⟩ implement ⟩ HTML templates
<template> tags (and their children):
never rendered by web browser.
only useful on web pages that use JavaScript.
can be cloned by template.content.cloneNode().
when cloning/inserting template.content into document, the fragment itself will not be inserted, but its children will.
Use a <template> element to clone DOM, instead of setting shadowRoot.innerHTML. 👉 Custom Elements ⟩ Element-defined Content
HTML templates examples
can put
<style>
and<script>
into<template>
as well.
<!-- styles and scripts in template -->
<template>
<style>
p { font-weight: bold; }
</style>
<script>
alert("Hello");
</script>
</template>
content becomes live (styles apply, scripts run etc) when inserted into document.
<!-- template -->
<template id="tmpl">
<script>
console.log("Hello");
</script>
<div class="message">Hello, world!</div>
</template>
<!-- script -->
<script>
let div = document.createElement('div');
// ⭐️ clone template content
// tmpl : HTMLTemplateElement
// tmpl.content : DocumentFragment
// node.cloneNode(): Node (return type)
div.append(tmpl.content.cloneNode(true));
// ⭐️ inserted into document
// ⭐️ now script (from <template>) runs
document.body.append(div);
</script>
we can use
<template>
to populate shadow root.
📁 script.js 👉 replit
div.onclick = function() {
// attach shadow root to <div> (shadow host)
let root = div.attachShadow({mode: 'open'});
// clone template content (<style>, <p>)
let clonedContent = tmpl.content.cloneNode(true);
// append to shadow root
// ⭐️ 注意:light DOM (text node: "Click me") 被 shadow DOM 取代了❗️
root.append(clonedContent);
let p = root.$('#message');
p.innerHTML = "Hello from the shadows❗️";
};
📁 index.html
<!-- ⭐️ template -->
<template id="tmpl">
<style>
p {
font-weight: bold;
margin: 0 auto;
}
</style>
<p id="message"></p>
</template>
<!-- shadow host -->
<div id="div">Click me❗️</div>
<!-- scripts -->
<script src="helpers.js"></script>
<script src="script.js"></script>
<!-- web component -->
<my-component>
a "none" error message
</my-component>
<my-component kind="warning">
this is a warning
</my-component>
<my-component kind="error">
this is an error message
</my-component>
// ⭐️ 1. custom web component
class MyComponent extends HTMLElement {
// constructor
constructor() {
// tell HTMLElement to initialize itself.
super();
}
// choose which template to use
connectedCallback() {
// create <div> elements
this.templates = document.createElement('div');
this.container = document.createElement('div');
// ⭐️ add a shadow DOM to component
// to activate/deactivate templates
this.root = this.attachShadow({mode: 'open'});
this.root.appendChild(this.templates);
this.root.appendChild(this.container);
// fill in templates
this.templates.innerHTML = MyComponent.template();
// choose which template to use
const kind = this.getAttribute(`kind`) || `none`;
const template = this.templates.querySelector(`template.${kind}-type`);
if (template) {
const clone = template.content.cloneNode(true);
this.container.innerHTML = '';
this.container.appendChild(clone);
}
}
// template HTML
static template() {
// 3 templates
// - template.warning-type
// - template.error-type
// - template.none-type
return `
<template class="warning-type">
<style>
.warning {
background-color: yellow;
padding: 15px;
color: red;
}
</style>
<div class="warning">
<slot>Error component<slot>
</div>
</template>
<template class="error-type">
<style>
.error {
background-color: red;
padding: 15px;
color: yellow;
}
</style>
<div class="error">
<slot>Error component<slot>
</div>
</template>
<template class="none-type">
<style>
.none {
background-color: gray;
padding: 15px;
color: #eee;
}
</style>
<div class="none">
<slot>Error component<slot>
</div>
</template>
`;
}
}
// ⭐️ 2. custom tag <my-component>
// ⭐️⭐️ custom element names must contain a "hyphen".
customElements.define('my-component', MyComponent);
Last updated