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); }); });Kopieren
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.