HTML-Template-Element und cloneNode
Das HTML-template-Element enthält ein HTML-Fragment – z.B. Zeilen einer Tabelle, figure-Tags mit figcaption und img. Der Inhalt des template-Elements wird auf der Seite erst angezeigt, wenn Javascript das Fragment klont und ins DOM einfügt.
Javascript Template-Engines
Wer PHP programmiert, kennt Template-Systeme wie Smarty oder Twigg: Templates sind Vorlagen aus HTML für den wiederholten Einsatz. Mehr oder minder alle Programmiersprachen arbeiten mit Template-Systemen.
Diese Templates sind immer dann effizient, wenn HTML-Elemente auf eine Anforderung hin mehrfach eingefügt werden sollen. Javascript hat von Haus aus kein Template-System im Angebot. HTML-Elemente werden aufwändig mit createElement erzeugt und zu einem Fragment zusammengesetzt. Die Alternative sind Javascript Template Engines wie
Ähnlich wie in PHP nutzen Javascript Template Engines besondere Zeichenkombinationen oder Direktiven:
EJS <% %>
Mustache {{ }}
Javascript Template-Systeme werden z.B. in NodeJS eingesetzt, aber sie können auch ohne Node ausgeführt werden.
HTML-Templates für Javascript
HTML bietet ein spezielles Template-Tag für Javascript, das mit Javascript cloneNode in »echte« HTML-Fragmente umgewandelt und eingebunden wird.
Vorher ist das Markup innerhalt des Template-Elements kein Teil des DOMs und kann auch nicht mit Methoden wie document.getElementById angesprochen werden. Inhalte eines Template-Tags werden erst heruntergeladen, wenn der Template-Code offiziell geklont und eingebunden ist: Bilder in einem Template-Tag werden nicht geladen.
<div id="book-list"> <!-- Platzhalter werden per JS ersetzt --> </div>
<template id="book-template"> <div class="book-card"> <img src="" alt="" loading="lazy" width="" height=""> <hgroup></hgroup> <div class="cards-category"></div> </div> </template>
const container = document.getElementById("book-list");
const template = document.getElementById("book-template");
// Erst Observer definieren!
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const placeholder = entry.target;
const book = JSON.parse(placeholder.dataset.book);
const clone = template.content.cloneNode(true);
const card = clone.querySelector(".book-card");
const img = card.querySelector("img");
const hgroup = card.querySelector("hgroup");
const p = card.querySelector("p");
const cat = card.querySelector(".cards-category");
img.src = book.img;
img.alt = book.titel;
img.width = book.width;
img.height = book.height;
hgroup.textContent = book.titel;
p.textContent = book.autor;
cat.textContent = book.type;
// Klasse für Transition nach dem nächsten Frame
requestAnimationFrame(() => {
card.classList.add("visible");
});
placeholder.replaceWith(clone);
observer.unobserve(placeholder);
}
});
}, {
rootMargin: "200px",
threshold: 0.01
});
// Buchdaten laden und Platzhalter erzeugen
fetch('books.json')
.then(res => res.json())
.then(books => {
books.slice(0,8).forEach(book => {
const div = document.createElement("div");
div.dataset.book = JSON.stringify(book);
div.style.minHeight = "200px";
container.appendChild(div);
observer.observe(div);
});
});
Das Template-Beispiel für die kleine Liste von Buch-Cards ist schlicht und kann im head- oder an belieber Stelle im body-Element stehen.
Das Schöne an den schlichten Template-Elementen aus purem HTML: Für Wiederholungen der Elemente und für Abfragen werden keine speziellen Direktiven gebraucht, sondern einfach nur Javascript in Reinform.
Loop in Handlebars
{{#each array}} {{@index}}: {{this}} {{/each}}
Loop Javascript
for (const elem of slides) { … }
Template Literals – native Javascript Template Engine
Template Literal ist mit ES6 auf den Plan getreten und ersetzt das Katzenhaarknäuel von verschachtelten einfachen und doppelten Hochkommas, +- und \-Zeichen der Mischung aus Strings und Variablen.
Eine typische Anwendung für Javascript Templates ist das dynamische Erstellen von Listeneinträgen und Tabellenzeilen in Anwendungen, wenn z.B. Elemente in einem JSON-Array geliefert und als Tabelle oder Liste dargestellt werden sollen.
const lager = [
{"frucht":"🌽", "ger":139, "austria":20, "switzerland":11 },
{"frucht":"🍆", "ger":170, "austria":29, "switzerland":9 },
{"frucht":"🍅", "ger":163, "austria":21, "switzerland":12 },
{"frucht":"🍇", "ger":109, "austria":13, "switzerland":4 },
{"frucht":"🍎", "ger":115, "austria":17, "switzerland":8 }
];
let template = lager.map(item => {
return `
<div class="entry">
<span class="frucht">${item.frucht}</span>
<span class="num ger">${item.ger}</span>
<span class="num austria">${item.austria}</span>
<span class="num switzerland">${item.switzerland}</span>
</div>
`;
}).join("");
document.querySelector("fruit-shop").innerHTML = template;
Eleganter als HTML-Templates für Javascript allemal, und eine native Javascript-Template-Engine anstelle der wechselnden Template Engines von Handlebar bis Moustach.