JavaScript/Tutorials/DOM/DOM-Manipulation

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Wenn ein Anwender mit der Webseite interagiert, ist es oft nötig, je nach erfolgter Eingabe unterschiedliche Inhalte zur Verfügung zu stellen.

So könnte ein Login flexibel werden: Wenn der Benutzer schon registriert ist, kann er nach dem Einloggen einfach weitermachen, für neue Nutzer werden je nach Stand der Eingabe unterschiedliche Inhalte wie ein Anmeldeformular dynamisch nachgeladen.

Auch bei einem Bildwechsler benötigt man die Zurück und Weiter-Buttons erst in der Großansicht.

Dieses Tutorial zeigt, wie Sie Ihre Webseite dynamisch erweitern, indem Sie neue Elemente erzeugen und in die Webseite einfügen.

Elemente dynamisch erzeugen

Gerade bei Spielen wird das Spielfeld oft erst geladen, wenn der Benutzer die Spielanleitung oder den bisherigen Punktestand (Highscore) gelesen hat, da das Hin- und Herklicken zwischen verschiedenen Webseiten zu umständlich wäre.

Hierfür können Sie Inhalte dynamisch ausgeben, indem Sie HTML-Elemente erzeugen, mit Inhalt füllen und in das DOM der Webseite einhängen:


Absätze dynamisch einfügen ansehen …
<button id="button">Drück mich!</button>
<div id="textblock">
   <p>Dies ist ein Textblock, dem dynamisch weitere Absätze angehängt werden können.</p>
</div>
Die Webseite enthält einen Button und ein div, in dem sich ein Textabsatz befindet.
document.addEventListener('DOMContentLoaded', function () {

  let text = 'Dies ist ein neuer Absatz'; 
 
  document.getElementById('button').addEventListener('click', createElement);

  function createElement(){
    let container = document.getElementById('textblock');
    let newElm = document.createElement('p');
    newElm.innerText = text;
    container.appendChild(newElm);
  }
 
});

Das Script ruft auf Klick die Funktion createElement() auf.
Dies erzeugt mit createElement ein neues p-Element und weist es der Variablen newElm zu. Dem Absatz wird mit innerText eine in der Variablen text enthaltenen Zeichenkette als Textknoten an das Element hinzugefügt. Anschließend wird das so dynamisch erzeugte Element mit appendChild in das DOM eingehängt.
Wenn Sie es mit der Konsole untersuchen, werden Sie keinen Unterschied zu normalen Textabsätzen finden.


eine Helferfunktion für neue Elemente

Mit der oberen Funktion konnten neue Absätze erzeugt werden. Für den Alltagseinsatz benötigt man aber eine Helfer-Funktion, mit der beliebige neue Elemente an beliebigen Stellen im DOM erzeugt werden.

Helferfunktion ansehen …
document.addEventListener('DOMContentLoaded', function () {

  let text1 = 'Dies ist ein neuer Absatz!'; 
  let text2 = 'Dies ist ein neuer Button!';   

 
  document.getElementById('button1').addEventListener('click', function() {
    createElement('#textblock', 'p', text1);
  });
  document.getElementById('button2').addEventListener('click', function() {
    createElement('#textblock', 'button', text2);
  });	

  function createElement(parent,elem, content){
    let container = document.querySelector(parent);
    let newElm  = document.createElement(elem);
    newElm .innerText = content;
    container.appendChild(newElm );
  }
 
});

Die Funktion createElement() wurde jetzt so erweitert, dass ihr Parameter übergeben werden können.
Beim Anhängen der Event-Handler wird addEventListener als zweiter Parameter eine anonyme Funktion übergeben, in der unsere Parameter gekapselt sind.

  • Der erste Parameter parent bestimmt, an welcher Stelle im Elementbaum das neue Element eingehängt wird.
  • elem legt fest, welches Element erzeugt wird.
  • content übergibt einen Inhalt, der dann als Textknoten eingefügt wird.


Ein Manko dieser Helferfunktion ist die fehlende Möglichkeit, weitere Klassen und Attribute festzulegen. So würde bei einem Bild oder einem Link ja zwingend eine URL benötigt.

Solche Helferfunktionen können Sie sich aber bei github kopieren oder selbst zusammenstellen.

Elemente dynamisch entfernen

Sie können Elemente dynamisch erzeugen - sie aber auch dynamisch wieder entfernen. Dafür müssen Sie mit der parentNode-Eigenschaft den Elternknoten finden und dann dessen Kind (also das gewünschte Element) mit removeChild wieder entfernen.

Elemente entfernen ansehen …
document.addEventListener('DOMContentLoaded', function () {
  document.addEventListener('click', removeElement);	
    
	
  function removeElement(e) {
    let elem = e.target;
    let main = document.querySelector('main');
    if (main != elem) {
      let parent = elem.parentNode;
      parent.removeChild( elem);
      return false;
    }
  }

});

In diesem Beispiel können Sie einzelne Elemente aus der Webseite löschen. Dafür wird mit event.target ermittelt, in welchem Element das Ereignis aufgetreten ist und dieser Wert der Variable elem zugewiesen.
Damit nicht die gesamte Seite gelöscht wird, überprüft man in einer bedingten Anweisung, ob das geklickte Ereignis im main-Element auftrat.
Bei allen anderen Elementen wird mit parentNode der Elternknoten ermittelt und dann mit removeChild(elem) das angeklickte Element entfernt.

Helferfunktion

Elemente entfernen
function removeElement(elem) {
    let body = document.querySelector('body');
    if (body != elem) {
      let parent = elem.parentNode;
      parent.removeChild( elem);
      return false;
    }
}

Diese Helferfunktion löscht jedes übergebene Element, überprüft aber, ob es sich dabei um den body handelt. In diesem Falle würde nichts entfernt werden.

Bildwechsler

Die oben gezeigten Methoden wollen wir nun in einem weiterführenden Anwendungsbeispiel ausprobieren: Im SELF-Forum wurde gefragt, wie man einen Bildwechsler (image-slider) programmiert, der sich mehrfach laden lässt. Deshalb wollen wir für eine Webseite mit mehreren Bildergruppen ein Script programmieren, das …

  • das ausgewählte Bild in einer Großansicht zeigt
  • Buttons zur Verfügung stellt, die eine weitere Auswahl durch den Nutzer ermöglichen.
  • erkennt, welche Bildergruppe angeklickt wird

HTML-Markup

Da es in JavaScript nicht möglich ist, auf Unterseiten oder das Dateiverzeichnis des Servers zuzugreifen, sollten die Bilder (oder deren URLs) schon auf der Webseite notiert sein.

Großansicht ohne JS ansehen …
<section id="peru" class="gallery">  
  <h2>Peru 2007</h2>

  <a href="peru-3.jpg">
  	<img src="peru-3-sm.jpg" alt="Peru 2007: Machu Picchu">
  </a>  
	<a href="peru-4.jpg">
  	<img src="peru-4-sm.jpg" alt="Peru 2007: Machu Picchu - Lamas in den Ruinen">
  </a>  
	<a href="peru-5.jpg">
  	<img src="peru-5-sm.jpg" alt="Peru 2007: Uros-Inseln im Titicaca-See">
  </a> 
  ...
</section>

Dieses HTML funktioniert bereits ohne JavaScript:

Das im img notierte kleine Bild wird angezeigt. Bei einem Klick darauf wird das im a-Element referenzierte große Bild geladen und im Browser angezeigt. So wird das im letzten Kapitel erwähnte Standardverhalten der HTML-Elemente genutzt.

Beachten Sie: Auf den Einsatz von Klassen für thumbnails und die Großansichten wurde verzichtet. Über .gallery a bzw. .gallery img kann jedes Element mit CSS oder JavaScript selektiert werden.

Bildertausch mit JavaScript

MIt einem Script soll die im href-Attribut notierte URL des großen Bilds für eine Darstellung innerhalb der Webseite genutzt werden.

Großansicht mit JS ansehen …
  document.querySelector('.gallery').addEventListener('click',function (evt) {
    evt.preventDefault();
		let element = event.target;
		let parentURL = element.parentNode.href;
		element.src = parentURL;
		element.classList.add('current');
  });

Nach den Regeln des unobtrusive JavaScript wird das Script nicht mit dem HTML vermischt, sondern im head notiert.

Mit AddEventHandler wird dem angeklickten Element eine Funktion zugewiesen.

Diese Funktion …

  1. verhindert mit Event.preventDefault das Aufrufen des Links
  2. ermittelt das auslösende Element
  3. ermittelt mit parentNode das Elternelement des Bilds, liest die URL des href-Attributs aus und …
  4. setzt diese in das src-Attribut des angeklickten Bilds.
  5. Damit dies größer dargestellt wird, erhält es mit classList.add() eine neue Klasse.

Mit jedem geklickten Bild wird ein weiteres mit der Klasse current (engl. für 'aktuell') auf Großansicht umgestellt, die bereits geklickten bleiben groß.

Eine solche Klasse kann man aber auch wieder entfernen:

Großansicht nur für ein Bild ansehen …
 1   let allPics = document.querySelectorAll('.gallery img');
 2   console.log('Anzahl Bilder: ' + allPics.length)
 3 
 4   document.querySelector('.gallery').addEventListener('click',function (evt) {
 5     evt.preventDefault();
 6     let element   = event.target,
 7         parentURL = element.parentNode.href;
 8     // bisherige Klassenzuweisungen entfernen		
 9     for (let pic of allPics) {
10       pic.classList.remove('current');
11     };		
12     // dem ausgewählten Bild die URL der Großansicht und die Klasse 'current' zuweisen		
13     element.src = parentURL;
14     element.classList.add('current');
15     // get the number
16     let idx = index(element);
17     console.log('geklicktes Bild: ' + idx);
18   });
19   
20   function index(el) {
21     for (let i=0; i < allPics.length; i++) {
22       if (allPics[i] == el) {
23         return i;
24       }
25     }
26     return -1;
27   }

Mit querySelectorAll können wir alle Elemente, die vom Selektor .gallery img, also alle img-Elemente, die Kinder und Kindeskinder des Elements mit der Klasse gallery sind, finden. Das Ergebnis wird als statische NodeList der Variable allPics zugewiesen.

Vor die dynamische Großansicht schieben wir nun in Zeile 9 eine for...of-Schleife ein, die alle Bilder durchläuft und ihnen mit classList.remove() die eventuell vorhandene Klasse current entfernt.

Störend wirkt aber, dass die thumbnails sowohl ober- als auch unterhalb der Großansicht dargestellt sind. Dies soll im nächsten Schritt verbessert werden.


Empfehlung: Das hier in den letzten Jahren vorgestellte Beispiel wurde aktualisiert und als Lightbox mit Bildwechsler in die Reihe Bilder im Internet verschoben.


Siehe auch

  • Bildwechsler
    Carousel-icon.svg
  • Web Animations (WAAPI)
    • Animieren in JavaScript
    • Animationen steuern
  • Fullscreen-Ansicht

    (Bild mit Lightbox-Effekt)