Nehmen wir an, wir möchten etwas nach dem anfänglichen Laden zu einer Webseite hinzufügen. JavaScript bietet uns eine Vielzahl von Werkzeugen. Vielleicht haben Sie einige davon verwendet, wie append, appendChild, insertAdjacentHTML oder innerHTML.
Das Schwierige beim Anhängen und Einfügen von Dingen mit JavaScript liegt weniger in den Werkzeugen, die es bietet, sondern darin, welches Werkzeug wann verwendet werden soll und wie jedes einzelne funktioniert.
Lassen Sie uns versuchen, die Dinge zu klären.
Sehr kurzer Kontext
Es kann hilfreich sein, ein wenig Hintergrund zu besprechen, bevor wir beginnen. Auf einfachster Ebene ist eine Website eine HTML-Datei, die von einem Server an einen Browser heruntergeladen wird.

Ihr Browser wandelt die HTML-Tags in Ihrer HTML-Datei in eine Reihe von Objekten um, die mit JavaScript manipuliert werden können. Diese Objekte bilden einen Document Object Model (DOM)-Baum. Dieser Baum ist eine Reihe von Objekten, die als Eltern-Kind-Beziehungen strukturiert sind.
Im DOM-Jargon werden diese Objekte als Knoten oder genauer gesagt als HTML-Elemente bezeichnet.
<!-- I'm the parent element -->
<div>
<!-- I'm a child element -->
<span>Hello</span>
</div>
In diesem Beispiel ist das HTML-span-Element das *Kind* des div-Elements, das der *Elternteil* ist.
Und ich weiß, dass einige dieser Begriffe seltsam und möglicherweise verwirrend sind. Wir sagen „Knoten“, aber manchmal sagen wir stattdessen auch „Element“ oder „Objekt“. Und in einigen Fällen beziehen sie sich auf dasselbe, je nachdem, wie spezifisch wir sein wollen.
Zum Beispiel ist ein „Element“ eine spezielle Art von „Knoten“, so wie ein Apfel eine spezielle Art von Frucht ist.
Wir können diese Begriffe von allgemein bis spezifisch ordnen: Objekt → Knoten → Element → HTML-Element
Das Verständnis dieser DOM-Elemente ist wichtig, da wir mit ihnen interagieren werden, um Dinge mit JavaScript nach dem ersten Laden der Seite hinzuzufügen und anzuhängen. Tatsächlich wollen wir damit beginnen.
Setup
Diese Anhänge- und Einfügemethoden folgen meist diesem Muster
Element.append_method_choice(stuff_to_append)
Auch hier ist ein Element lediglich ein Objekt im DOM-Baum, das etwas HTML darstellt. Zuvor erwähnten wir, dass der Zweck des DOM-Baums darin besteht, uns eine bequeme Möglichkeit zu geben, mit HTML über JavaScript zu interagieren.
Wie können wir also mit JavaScript ein HTML-Element abrufen?
Abfragen des DOM
Nehmen wir an, wir haben folgendes kleines bisschen HTML
<div id="example" class="group">
Hello World
</div>
Es gibt ein paar gängige Möglichkeiten, das DOM abzufragen
// Query a specific selector (could be class, ID, element type, or attribute):
const my_element1 = document.querySelector('#example')
// Query an element by its ID:
const my_element2 = document.getElementbyId('example')
// Query an element by its class:
const my_element3 = document.getElementsbyClassName('group')[0]
In diesem Beispiel fragen alle drei Zeilen dasselbe ab, suchen es aber auf unterschiedliche Weise. Eine schaut auf beliebige der CSS-Selektoren des Elements; eine schaut auf die ID des Elements; und eine schaut auf die Klasse des Elements.
Beachten Sie, dass die Methode getElementbyClass ein Array zurückgibt. Das liegt daran, dass sie mehrere Elemente im DOM abgleichen kann und die Speicherung dieser Übereinstimmungen in einem Array sicherstellt, dass alle berücksichtigt werden.
Was wir anhängen und einfügen können
// Append Something
const my_element1 = document.querySelector('#example')
my_element1.append(something)
In diesem Beispiel ist something ein Parameter, der Zeug darstellt, das wir an das Ende des abgeglichenen Elements anhängen möchten (d. h. anfügen).
Wir können nicht einfach beliebige Dinge an beliebige Objekte anhängen. Die append-Methode erlaubt uns nur, entweder einen Knoten oder einfachen Text an ein Element im DOM anzuhängen. Aber einige andere Methoden können auch HTML an DOM-Elemente anhängen.
- Knoten werden entweder mit
document.createElement()in JavaScript erstellt oder mit einer der Abfragemethoden ausgewählt, die wir im letzten Abschnitt betrachtet haben. - Einfacher Text ist eben Text. Er ist einfacher Text in dem Sinne, dass er keine HTML-Tags oder Formatierungen mit sich führt (z. B.
Hallo). - HTML ist ebenfalls Text, aber im Gegensatz zu einfachem Text wird er beim Hinzufügen zum DOM als Markup geparst (z. B.
<div>Hallo</div>).
Es könnte hilfreich sein, genau aufzuschlüsseln, welche Parameter von welchen Methoden unterstützt werden
| Methode | Knoten | HTML-Text | Text |
|---|---|---|---|
append | Ja | Nein | Ja |
appendChild | Ja | Nein | Nein |
insertAdjacentHTML | Nein | Ja | Ja1 |
innerHTML2 | Nein | Ja | Ja |
insertAdjacentText wird empfohlen.2 Anstatt traditioneller Parameter zu verwenden, wird
innerHTML wie folgt verwendet: element.innerHTML = 'HTML-String'Wie man wählt, welche Methode man verwendet
Nun, es hängt wirklich davon ab, was Sie anhängen möchten, ganz zu schweigen von bestimmten Eigenheiten des Browsers, die zu berücksichtigen sind.
- Wenn Sie vorhandenes HTML haben, das an Ihr JavaScript gesendet wird, ist es wahrscheinlich am einfachsten, mit Methoden zu arbeiten, die HTML unterstützen.
- Wenn Sie neues HTML in JavaScript erstellen, kann die Erstellung eines Knotens mit viel Markup umständlich sein, während HTML weniger ausführlich ist.
- Wenn Sie sofort Ereignis-Listener anhängen möchten, sollten Sie mit Knoten arbeiten, da wir
addEventListenerauf Knoten und nicht auf HTML aufrufen. - Wenn Sie nur Text benötigen, ist jede Methode, die einfache Textparameter unterstützt, in Ordnung.
- Wenn Ihr HTML potenziell nicht vertrauenswürdig ist (d. h. es stammt von Benutzereingaben, z. B. einem Kommentar zu einem Blogbeitrag), sollten Sie bei der Verwendung von HTML vorsichtig sein, es sei denn, es wurde bereinigt (d. h. der schädliche Code wurde entfernt).
- Wenn Sie Internet Explorer unterstützen müssen, dann ist die Verwendung von
appendausgeschlossen.
Beispiel
Nehmen wir an, wir haben eine Chat-Anwendung und möchten einen Benutzer, Dale, zu einer Freundesliste hinzufügen, wenn er sich anmeldet.
<!-- HTML Buddy List -->
<ul id="buddies">
<li><a>Alex</a></li>
<li><a>Barry</a></li>
<li><a>Clive</a></li>
<!-- Append next user here -->
</ul>
Hier ist, wie wir dies mit jeder der oben genannten Methoden erreichen würden.
append
Wir müssen ein Knotenobjekt erstellen, das sich in <li><a>Dale</a></li> übersetzt.
const new_buddy = document.createElement('li')
const new_link = document.createElement('a')
const buddy_name = "Dale"
new_link.append(buddy_name) // Text param
new_buddy.append(new_link) // Node param
const list = document.querySelector('#buddies')
list.append(new_buddy) // Node param
Unser endgültiges append platziert den neuen Benutzer am Ende der Freundesliste, direkt vor dem schließenden </ul>-Tag. Wenn wir den Benutzer lieber am Anfang der Liste platzieren möchten, könnten wir stattdessen die Methode prepend verwenden.
Sie haben vielleicht bemerkt, dass wir append auch verwenden konnten, um unser <a>-Tag mit Text wie folgt zu füllen
const buddy_name = "Dale"
new_link.append(buddy_name) // Text param
Dies unterstreicht die Vielseitigkeit von append.
Und nur um es noch einmal hervorzuheben, append wird in Internet Explorer nicht unterstützt.
appendChild
appendChild ist eine weitere JavaScript-Methode zum Anhängen von Dingen an DOM-Elemente. Sie ist etwas eingeschränkt, da sie nur mit Knotenobjekten funktioniert, sodass wir Hilfe von textContent (oder innerText) für unsere reinen Textanforderungen benötigen.
Beachten Sie, dass appendChild im Gegensatz zu append in Internet Explorer unterstützt wird.
const new_buddy = document.createElement('li')
const new_link = document.createElement('a')
const buddy_name = "Dale"
new_link.textContent = buddy_name
new_buddy.appendChild(new_link) // Node param
const list = document.querySelector('#buddies')
list.appendChild(new_buddy) // Node param
Bevor wir weitermachen, betrachten wir ein ähnliches Beispiel, aber mit stärkerem Markup.
Nehmen wir an, das HTML, das wir anhängen wollten, sah nicht aus wie <li><a>Dale</a></li>, sondern eher wie
<li class="abc" data-tooltip="Click for Dale">
<a id="user_123" class="def" data-user="dale">
<img src="images/dale.jpg" alt="Profile Picture"/>
<span>Dale</span>
</a>
</li>
Unser JavaScript würde ungefähr so aussehen
const buddy_name = "Dale"
const new_buddy = document.createElement('li')
new_buddy.className = 'abc'
new_buddy.setAttribute('data-tooltip', `Click for ${buddy_name}`)
const new_link = document.createElement('a')
new_link.id = 'user_123'
new_link.className = 'def'
new_link.setAttribute('data-user', buddy_name)
const new_profile_img = document.createElement('img')
new_profile_img.src = 'images/dale.jpg'
new_profile_img.alt = 'Profile Picture'
const new_buddy_span = document.createElement('span')
new_buddy_span.textContent = buddy_name
new_link.appendChild(new_profile_img) // Node param
new_link.appendChild(new_buddy_span) // Node param
new_buddy.appendChild(new_link) // Node param
const list = document.querySelector('#buddies')
list.appendChild(new_buddy) // Node param
Es gibt keinen Grund, all das obige JavaScript zu befolgen – der Punkt ist, dass die Erstellung großer Mengen HTML in JavaScript ziemlich umständlich werden kann. Und dem kann man nicht entkommen, wenn wir append oder appendChild verwenden.
In diesem Szenario mit starkem Markup wäre es schön, unser HTML einfach als Zeichenkette schreiben zu können, anstatt eine Reihe von JavaScript-Methoden zu verwenden…
insertAdjacentHTML
insertAdjacentHTML ist wie append, da es auch Dinge zu DOM-Elementen hinzufügen kann. Ein Unterschied ist jedoch, dass insertAdjacentHTML diese Dinge an einer bestimmten Position relativ zum abgeglichenen Element einfügt.
Und es funktioniert zufällig mit HTML. Das bedeutet, wir können tatsächliches HTML in ein DOM-Element einfügen und genau bestimmen, wo wir es mit vier verschiedenen Positionen haben wollen
<!-- beforebegin -->
<div id="example" class="group">
<!-- afterbegin -->
Hello World
<!-- beforeend -->
</div>
<!-- afterend -->
So können wir die Idee, unser HTML zu „appenden“, ungefähr nachbilden, indem wir es an der Position beforeend des #buddies-Selectors einfügen
const buddy_name = "Dale"
const new_buddy = `<li><a>${buddy_name}</a></li>`
const list = document.querySelector('#buddies')
list.insertAdjacentHTML('beforeend', new_buddy)
Erinnern Sie sich an die Sicherheitsbedenken, die wir zuvor erwähnt haben. Wir sollten niemals von einem Endbenutzer eingegebenes HTML einfügen, da wir uns sonst anfällig für Cross-Site-Scripting-Schwachstellen machen würden.
innerHTML
innerHTML ist eine weitere Methode zum Einfügen von Dingen. Dennoch wird sie zum Einfügen nicht empfohlen, wie wir sehen werden.
Hier ist unsere Abfrage und das HTML, das wir einfügen möchten
const buddy_name = "Dale"
const new_buddy = `<li><a>${buddy_name}</a></li>`
const list = document.querySelector('#buddies')
list.innerHTML += new_buddy
Anfänglich scheint das zu funktionieren. Unsere aktualisierte Freundesliste sieht im DOM so aus
<ul id="buddies">
<li><a>Alex</a></li>
<li><a>Barry</a></li>
<li><a>Clive</a></li>
<li><a>Dale</a></li>
</ul>
Das ist es, was wir wollen! Aber es gibt eine Einschränkung bei der Verwendung von innerHTML, die uns daran hindert, Ereignis-Listener für Elemente innerhalb von #buddies zu verwenden, aufgrund der Natur von += in list.innerHTML += new_buddy.
Sie sehen, A += B verhält sich genauso wie A = A + B. In diesem Fall ist A unser vorhandenes HTML und B ist das, was wir ihm hinzufügen. Das Problem ist, dass dies zu einer Kopie des vorhandenen HTML mit dem zusätzlich eingefügten HTML führt. Und Ereignis-Listener können keine Kopien überwachen. Das bedeutet, wenn wir auf eines der <a>-Tags in der Freundesliste für ein Klickereignis hören wollen, verlieren wir diese Fähigkeit mit innerHTML.
Also, nur eine Warnung.
Demo
Hier ist eine Demo, die alle von uns behandelten Methoden zusammenfasst. Das Klicken auf die Schaltfläche jeder Methode fügt „Dale“ als Element zur Freundesliste hinzu.
Öffnen Sie dazu auch die DevTools und sehen Sie, wie das neue Listenelement zum DOM hinzugefügt wird.
Zusammenfassung
Hier ist ein allgemeiner Überblick über unseren Stand, wenn wir Dinge in das DOM anhängen und einfügen. Betrachten Sie es als Spickzettel für den Fall, dass Sie Hilfe bei der Entscheidung benötigen, welche Methode Sie verwenden sollen.
| Methode | Knoten | HTML-Text | Text | Internet Explorer? | Ereignis-Listener | Sicher? | HTML-Templating |
|---|---|---|---|---|---|---|---|
append | Ja | Nein | Ja | Nein | Bewahrt | Ja | Mittel |
appendChild | Ja | Nein | Nein | Ja | Bewahrt | Ja | Mittel |
insertAdjacentHTML | Nein | Ja | Ja1 | Ja | Bewahrt | Vorsichtig | Einfach |
innerHTML2 | Nein | Ja | Ja | Ja | Verliert | Vorsichtig | Einfach |
insertAdjacentText wird empfohlen.2 Anstatt traditioneller Parameter zu verwenden, wird
innerHTML wie folgt verwendet: element.innerHTML = 'HTML-String'Wenn ich das alles in ein paar Empfehlungen zusammenfassen müsste
- Die Verwendung von
innerHTMLzum Anhängen wird nicht empfohlen, da sie Ereignis-Listener entfernt. appendfunktioniert gut, wenn Sie die Flexibilität der Arbeit mit Knotenelementen oder reinem Text mögen und Internet Explorer nicht unterstützen müssen.appendChildfunktioniert gut, wenn Sie gerne (oder müssen) mit Knotenelementen arbeiten und volle Browserabdeckung wünschen.insertAdjacentHTMList gut, wenn Sie HTML generieren müssen und eine genauere Kontrolle darüber wünschen, wo es im DOM platziert wird.
Tiefer graben
Die oben genannten Methoden werden häufig verwendet und sollten die Mehrheit Ihrer Anwendungsfälle abdecken.
Das gesagt, es gibt noch einige zusätzliche Anhänge-/Einfügemethoden, falls Sie neugierig sind
Letzter Gedanke und ein kurzer Hinweis :)
Dieser Beitrag wurde durch reale Probleme inspiriert, auf die ich kürzlich bei der Entwicklung einer Chat-Anwendung gestoßen bin. Wie Sie sich vorstellen können, ist eine Chat-Anwendung auf viel Anhängen/Einfügen angewiesen – Leute, die online kommen, neue Nachrichten, Benachrichtigungen usw.
Diese Chat-Anwendung heißt Bounce. Es ist ein Peer-to-Peer-Lern-Chat. Angenommen, Sie sind ein JavaScript-Entwickler (unter anderem), haben Sie wahrscheinlich etwas zu lehren! Und Sie können etwas zusätzliches Geld verdienen.
Wenn Sie neugierig sind, hier ist ein Link zur Homepage oder mein Profil auf Bounce. Prost!
Schöner Artikel. Erlauben Sie mir jedoch ein paar Anmerkungen.
Es sollte
document.getElementsByClassNameanstelle vondocument.getElementbyClasssein.Ich bin mir nicht sicher, warum Sie Klammern in diesem Code verwenden
new_link.className = ('def'). Können Sie das bitte erläutern?Hallo Konstantin, danke für die Hinweise. Ja, Sie haben in beiden Fällen Recht – der Beitrag wurde aktualisiert.
Ich denke, Sie lassen eine sehr wichtige Funktion aus, die zu Unrecht wenig bekannt ist, nämlich Document.createDocumentFragment(). Wir können mit dieser Funktion in geparstes HTML konvertieren (anstatt mit document.createElement) und dann das erstellte Fragment anhängen. Außerdem performanter, da es weniger Speicher benötigt. Also
const element = Document.createDocumentFragment(html_string);
el_parent.append(element);
Was denkst du?
Pau Sabater
Ich kann nur empfehlen, innerHTML zu verwenden.
Das Erstellen einer temporären, auch sehr großen Zeichenkette und deren Anwendung auf innerHTML ist meiner Erfahrung nach sehr schnell, auch auf Mobilgeräten.
Kann aber keine Ereignis-Listener verwenden (wie der Autor sagte).
Außerdem – insertBefore, before, after, replaceChildren, prepend. Und allgemeiner Ratschlag, Knoten auf einmal einzufügen, um Neuanordnungen zu reduzieren.
Ja, guter Rat – könnte das als Teil eines größeren Beitrags über die Leistungseigenschaften dieser Methoden betrachten.
Und Anmerkung zu
insertBefore,beforeundafter– ein Abschnitt *Tiefer graben* wurde hinzugefügt.Zusätzlich zu dem, was die anderen Kommentatoren erwähnt haben, haben Sie auch insertAdjacentElement vergessen, was seltsam ist, da Sie sowohl insertAdjacentHTML als auch insertAdjacentText erwähnt haben.
Ich würde auch Dokumentfragmente erwähnen, wenn viele Geschwister auf einmal eingefügt werden…
Habe
insertAdjacentElementzu einem Abschnitt *Tiefer graben* hinzugefügt, danke!Und gute Idee zu Dokumentfragmenten – es wäre interessant, Leistungseigenschaften und Techniken zur Optimierung zu vergleichen.
Ich bin auch ein großer Fan von
.replaceWith()!https://developer.mozilla.org/en-US/docs/Web/API/Element/replaceWith
.replaceChild()ist auch nett, aber umständlich, da man Referenzen auf 3 verschiedene Knoten abrufen muss, um es zu verwenden.