Anfänger182025-01-15

JavaScript DOM Manipulation - HTML mit JS ändern

Lerne JavaScript DOM: querySelector, addEventListener, createElement, innerHTML, classList, Styles ändern, Events und praktische Beispiele.

#javascript#dom#events#querySelector#addEventListener#manipulation

JavaScript DOM Manipulation

DOM (Document Object Model) ist die Schnittstelle zwischen JavaScript und HTML. Damit kannst du Webseiten dynamisch ändern!

Was ist das DOM?

Das DOM ist eine Baum-Struktur deiner HTML-Seite:

DOM Tree
<!-- HTML -->
<!DOCTYPE html>
<html>
  <head>
    <title>Meine Seite</title>
  </head>
  <body>
    <h1>Titel</h1>
    <p>Text</p>
  </body>
</html>

// DOM Baum:
// document
//   └─ html
//       ├─ head
//       │   └─ title
//       └─ body
//           ├─ h1
//           └─ p

Mit JavaScript kannst du:

  • ✅ Elemente auswählen
  • ✅ Content ändern
  • ✅ Styles ändern
  • ✅ Elemente erstellen/löschen
  • ✅ Auf Events reagieren

Elemente auswählen

querySelector() - Ein Element

querySelector
<!-- HTML -->
<h1 id="title">Hallo Welt</h1>
<p class="text">Ein Absatz</p>
<div class="container">
    <p>Noch ein Absatz</p>
</div>

<script>
// Nach ID
const title = document.querySelector('#title');
console.log(title);  // <h1 id="title">Hallo Welt</h1>

// Nach Class (erstes Element)
const text = document.querySelector('.text');
console.log(text);  // <p class="text">Ein Absatz</p>

// Nach Tag
const paragraph = document.querySelector('p');
console.log(paragraph);  // Erstes <p>

// Kombiniert
const containerP = document.querySelector('.container p');
console.log(containerP);  // <p> innerhalb von .container
</script>

CSS-Selektoren verwenden!

querySelectorAll() - Mehrere Elemente

querySelectorAll
<!-- HTML -->
<p class="text">Absatz 1</p>
<p class="text">Absatz 2</p>
<p class="text">Absatz 3</p>

<script>
// Alle Elemente mit .text
const texts = document.querySelectorAll('.text');
console.log(texts);  // NodeList(3)

// Über alle iterieren
texts.forEach(text => {
    console.log(text.textContent);
});
// Absatz 1
// Absatz 2
// Absatz 3

// Mit Index zugreifen
console.log(texts[0]);  // Erster Absatz
console.log(texts[1]);  // Zweiter Absatz
</script>

Alte Methoden (weniger nutzen)

Legacy Selectors
// getElementById
const el = document.getElementById('title');  // Ohne #!

// getElementsByClassName
const elements = document.getElementsByClassName('text');  // Ohne .!

// getElementsByTagName
const paragraphs = document.getElementsByTagName('p');

// ✅ BESSER: querySelector/All
const el2 = document.querySelector('#title');
const elements2 = document.querySelectorAll('.text');

Content ändern

textContent - Text ändern

textContent
<!-- HTML -->
<h1 id="title">Alter Titel</h1>
<p id="text">Alter Text</p>

<script>
const title = document.querySelector('#title');
const text = document.querySelector('#text');

// Text lesen
console.log(title.textContent);  // Alter Titel

// Text ändern
title.textContent = 'Neuer Titel';
text.textContent = 'Neuer Text mit <b>HTML</b>';  // HTML wird als Text angezeigt!

// Anhängen
text.textContent += ' Mehr Text';
</script>

innerHTML - HTML ändern

innerHTML
<!-- HTML -->
<div id="content">
    <p>Alter Content</p>
</div>

<script>
const content = document.querySelector('#content');

// HTML lesen
console.log(content.innerHTML);  // <p>Alter Content</p>

// HTML ändern
content.innerHTML = '<h2>Neuer Titel</h2><p>Neuer Text</p>';

// HTML hinzufügen
content.innerHTML += '<p>Noch mehr</p>';

// ⚠️ Vorsicht: XSS-Gefahr bei User-Input!
const userInput = '<script>alert("XSS")</script>';
content.innerHTML = userInput;  // ❌ Gefährlich!

// ✅ BESSER: textContent oder sanitize
content.textContent = userInput;  // Wird als Text angezeigt
</script>

Attribute ändern

Attributes
<!-- HTML -->
<img id="image" src="old.jpg" alt="Altes Bild">
<input id="input" type="text" value="Alt">
<a id="link" href="https://old.com">Link</a>

<script>
const img = document.querySelector('#image');
const input = document.querySelector('#input');
const link = document.querySelector('#link');

// Attribute lesen
console.log(img.src);       // https://domain.com/old.jpg
console.log(img.alt);       // Altes Bild
console.log(input.value);   // Alt
console.log(link.href);     // https://old.com

// Attribute ändern
img.src = 'new.jpg';
img.alt = 'Neues Bild';
input.value = 'Neu';
link.href = 'https://new.com';

// Attribute mit getAttribute/setAttribute
console.log(img.getAttribute('src'));
img.setAttribute('src', 'another.jpg');

// data-* Attribute
// <div id="user" data-id="123" data-role="admin"></div>
const user = document.querySelector('#user');
console.log(user.dataset.id);    // 123
console.log(user.dataset.role);  // admin
user.dataset.id = '456';
</script>

Styles ändern

Inline Styles
<!-- HTML -->
<div id="box">Box</div>

<script>
const box = document.querySelector('#box');

// Style ändern (camelCase!)
box.style.color = 'white';
box.style.backgroundColor = 'blue';
box.style.padding = '20px';
box.style.borderRadius = '10px';
box.style.fontSize = '24px';

// Mehrere Styles auf einmal
Object.assign(box.style, {
    color: 'white',
    backgroundColor: 'blue',
    padding: '20px',
    borderRadius: '10px'
});

// Style lesen
console.log(box.style.color);  // white

// Computed Style (inkl. CSS)
const computed = window.getComputedStyle(box);
console.log(computed.color);           // rgb(255, 255, 255)
console.log(computed.backgroundColor); // rgb(0, 0, 255)
</script>

Classes ändern - classList

Besser als inline styles!

classList
<!-- CSS -->
<style>
.active { background-color: blue; color: white; }
.large { font-size: 24px; }
.hidden { display: none; }
</style>

<!-- HTML -->
<div id="box" class="box">Box</div>

<script>
const box = document.querySelector('#box');

// Class hinzufügen
box.classList.add('active');
console.log(box.className);  // box active

// Mehrere Classes
box.classList.add('large', 'rounded');

// Class entfernen
box.classList.remove('active');

// Class togglen (an/aus)
box.classList.toggle('hidden');  // Fügt hinzu
box.classList.toggle('hidden');  // Entfernt wieder

// Prüfen ob Class vorhanden
if (box.classList.contains('active')) {
    console.log('Box ist active');
}

// Class ersetzen
box.classList.replace('active', 'inactive');

// Alle Classes
console.log(box.classList);  // DOMTokenList
</script>

Events - Auf Benutzer reagieren

addEventListener() - Event Listener

addEventListener
<!-- HTML -->
<button id="btn">Klick mich</button>
<input id="input" type="text">

<script>
const button = document.querySelector('#btn');
const input = document.querySelector('#input');

// Click Event
button.addEventListener('click', function() {
    console.log('Button geklickt!');
});

// Mit Arrow Function
button.addEventListener('click', () => {
    console.log('Button geklickt!');
});

// Input Event
input.addEventListener('input', (event) => {
    console.log('Eingabe:', event.target.value);
});

// Mehrere Listener
button.addEventListener('click', () => {
    console.log('Handler 1');
});

button.addEventListener('click', () => {
    console.log('Handler 2');
});
// Beide werden ausgeführt!
</script>

Event Object

Event Object
button.addEventListener('click', (event) => {
    // Event Object
    console.log(event.type);           // 'click'
    console.log(event.target);         // Das geklickte Element
    console.log(event.currentTarget);  // Element mit Listener

    // Maus-Position
    console.log(event.clientX, event.clientY);

    // Verhindern Default-Verhalten
    event.preventDefault();

    // Verhindern Event-Bubbling
    event.stopPropagation();
});

// Link verhindert zu folgen
const link = document.querySelector('a');
link.addEventListener('click', (e) => {
    e.preventDefault();
    console.log('Link Klick verhindert');
});

// Form Submit verhindern
const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
    e.preventDefault();
    console.log('Submit verhindert');
});

Häufige Events

Common Events
const element = document.querySelector('#element');

// Maus Events
element.addEventListener('click', () => {});       // Klick
element.addEventListener('dblclick', () => {});    // Doppelklick
element.addEventListener('mouseenter', () => {});  // Maus drüber
element.addEventListener('mouseleave', () => {});  // Maus weg
element.addEventListener('mousemove', () => {});   // Maus bewegt

// Keyboard Events
element.addEventListener('keydown', () => {});    // Taste gedrückt
element.addEventListener('keyup', () => {});      // Taste losgelassen
element.addEventListener('keypress', () => {});   // Taste gedrückt (veraltet)

// Form Events
element.addEventListener('submit', () => {});     // Form abgeschickt
element.addEventListener('input', () => {});      // Input geändert
element.addEventListener('change', () => {});     // Wert geändert
element.addEventListener('focus', () => {});      // Fokus erhalten
element.addEventListener('blur', () => {});       // Fokus verloren

// Scroll & Resize
window.addEventListener('scroll', () => {});      // Seite gescrollt
window.addEventListener('resize', () => {});      // Fenster resized

// Load
window.addEventListener('load', () => {});        // Seite geladen
document.addEventListener('DOMContentLoaded', () => {});  // DOM bereit

Elemente erstellen

createElement
<!-- HTML -->
<div id="container"></div>

<script>
const container = document.querySelector('#container');

// Element erstellen
const paragraph = document.createElement('p');

// Text hinzufügen
paragraph.textContent = 'Neuer Absatz';

// Attribute setzen
paragraph.className = 'text';
paragraph.id = 'myParagraph';

// Zum DOM hinzufügen
container.appendChild(paragraph);

// Mehrere Elemente
const heading = document.createElement('h2');
heading.textContent = 'Überschrift';

const text = document.createElement('p');
text.textContent = 'Text';

const button = document.createElement('button');
button.textContent = 'Klick mich';
button.addEventListener('click', () => {
    alert('Geklickt!');
});

// Alle hinzufügen
container.appendChild(heading);
container.appendChild(text);
container.appendChild(button);

// An bestimmter Position einfügen
container.insertBefore(heading, container.firstChild);

// prepend/append (modern)
container.prepend(heading);  // Am Anfang
container.append(button);    // Am Ende
</script>

Elemente löschen

Remove Elements
<!-- HTML -->
<div id="container">
    <p id="p1">Absatz 1</p>
    <p id="p2">Absatz 2</p>
    <p id="p3">Absatz 3</p>
</div>

<script>
const p1 = document.querySelector('#p1');
const p2 = document.querySelector('#p2');
const container = document.querySelector('#container');

// Element entfernen (modern)
p1.remove();

// Parent entfernen (alt)
container.removeChild(p2);

// Alle Kinder entfernen
container.innerHTML = '';

// Oder mit while
while (container.firstChild) {
    container.removeChild(container.firstChild);
}
</script>

Praktische Beispiele

Beispiel 1: Counter

Counter App
<!-- HTML -->
<div id="counter">
    <h2 id="count">0</h2>
    <button id="increment">+</button>
    <button id="decrement">-</button>
    <button id="reset">Reset</button>
</div>

<script>
let count = 0;
const countElement = document.querySelector('#count');
const incrementBtn = document.querySelector('#increment');
const decrementBtn = document.querySelector('#decrement');
const resetBtn = document.querySelector('#reset');

// Update Display
function updateDisplay() {
    countElement.textContent = count;
    countElement.style.color = count > 0 ? 'green' : count < 0 ? 'red' : 'black';
}

// Event Listeners
incrementBtn.addEventListener('click', () => {
    count++;
    updateDisplay();
});

decrementBtn.addEventListener('click', () => {
    count--;
    updateDisplay();
});

resetBtn.addEventListener('click', () => {
    count = 0;
    updateDisplay();
});
</script>

Beispiel 2: Todo Liste

Todo List
<!-- HTML -->
<div id="todoApp">
    <input id="todoInput" type="text" placeholder="Neue Aufgabe">
    <button id="addBtn">Hinzufügen</button>
    <ul id="todoList"></ul>
</div>

<script>
const input = document.querySelector('#todoInput');
const addBtn = document.querySelector('#addBtn');
const list = document.querySelector('#todoList');

function addTodo() {
    const text = input.value.trim();

    if (text === '') return;

    // Li erstellen
    const li = document.createElement('li');
    li.textContent = text;

    // Delete Button
    const deleteBtn = document.createElement('button');
    deleteBtn.textContent = 'Löschen';
    deleteBtn.addEventListener('click', () => {
        li.remove();
    });

    // Toggle Done
    li.addEventListener('click', () => {
        li.style.textDecoration = li.style.textDecoration === 'line-through'
            ? 'none'
            : 'line-through';
    });

    li.appendChild(deleteBtn);
    list.appendChild(li);

    input.value = '';
    input.focus();
}

addBtn.addEventListener('click', addTodo);

input.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
        addTodo();
    }
});
</script>

Beispiel 3: Theme Switcher

Dark Mode Toggle
<!-- HTML -->
<button id="themeToggle">Toggle Theme</button>

<!-- CSS -->
<style>
body.dark {
    background-color: #1a1a1a;
    color: white;
}
</style>

<script>
const toggle = document.querySelector('#themeToggle');

toggle.addEventListener('click', () => {
    document.body.classList.toggle('dark');

    // Text ändern
    if (document.body.classList.contains('dark')) {
        toggle.textContent = 'Light Mode';
    } else {
        toggle.textContent = 'Dark Mode';
    }

    // In localStorage speichern
    const theme = document.body.classList.contains('dark') ? 'dark' : 'light';
    localStorage.setItem('theme', theme);
});

// Beim Laden wiederherstellen
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
    document.body.classList.add('dark');
    toggle.textContent = 'Light Mode';
}
</script>

Beispiel 4: Modal/Popup

Modal Window
<!-- HTML -->
<button id="openModal">Modal öffnen</button>
<div id="modal" class="modal hidden">
    <div class="modal-content">
        <span id="closeModal" class="close">&times;</span>
        <h2>Modal Titel</h2>
        <p>Modal Content hier...</p>
    </div>
</div>

<!-- CSS -->
<style>
.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
}

.modal.hidden {
    display: none;
}

.modal-content {
    background-color: white;
    padding: 20px;
    border-radius: 10px;
    max-width: 500px;
}
</style>

<script>
const openBtn = document.querySelector('#openModal');
const closeBtn = document.querySelector('#closeModal');
const modal = document.querySelector('#modal');

openBtn.addEventListener('click', () => {
    modal.classList.remove('hidden');
});

closeBtn.addEventListener('click', () => {
    modal.classList.add('hidden');
});

// Schließen bei Klick außerhalb
modal.addEventListener('click', (e) => {
    if (e.target === modal) {
        modal.classList.add('hidden');
    }
});

// Schließen mit Escape
document.addEventListener('keydown', (e) => {
    if (e.key === 'Escape' && !modal.classList.contains('hidden')) {
        modal.classList.add('hidden');
    }
});
</script>

Beispiel 5: Form Validation

Form Validation
<!-- HTML -->
<form id="form">
    <input id="name" type="text" placeholder="Name" required>
    <span id="nameError" class="error"></span>

    <input id="email" type="email" placeholder="Email" required>
    <span id="emailError" class="error"></span>

    <button type="submit">Absenden</button>
</form>

<script>
const form = document.querySelector('#form');
const nameInput = document.querySelector('#name');
const emailInput = document.querySelector('#email');
const nameError = document.querySelector('#nameError');
const emailError = document.querySelector('#emailError');

// Live Validation
nameInput.addEventListener('input', () => {
    if (nameInput.value.length < 3) {
        nameError.textContent = 'Name zu kurz (min. 3 Zeichen)';
        nameError.style.color = 'red';
    } else {
        nameError.textContent = '';
    }
});

emailInput.addEventListener('input', () => {
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

    if (!emailPattern.test(emailInput.value)) {
        emailError.textContent = 'Ungültige Email';
        emailError.style.color = 'red';
    } else {
        emailError.textContent = '';
    }
});

// Submit
form.addEventListener('submit', (e) => {
    e.preventDefault();

    if (nameInput.value.length >= 3 && emailInput.value.includes('@')) {
        console.log('Form valid!');
        console.log({
            name: nameInput.value,
            email: emailInput.value
        });

        // Form zurücksetzen
        form.reset();
    }
});
</script>

Event Delegation

Effizienter für viele Elemente:

Event Delegation
<!-- HTML -->
<ul id="list">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
<button id="addItem">Item hinzufügen</button>

<script>
const list = document.querySelector('#list');
const addBtn = document.querySelector('#addItem');

// ❌ SCHLECHT: Listener für jedes Li
// list.querySelectorAll('li').forEach(li => {
//     li.addEventListener('click', () => {
//         li.style.textDecoration = 'line-through';
//     });
// });

// ✅ BESSER: Ein Listener auf Parent
list.addEventListener('click', (e) => {
    if (e.target.tagName === 'LI') {
        e.target.style.textDecoration = 'line-through';
    }
});

// Dynamische Elemente funktionieren auch!
addBtn.addEventListener('click', () => {
    const li = document.createElement('li');
    li.textContent = `Item ${list.children.length + 1}`;
    list.appendChild(li);
    // Klick funktioniert automatisch!
});
</script>

Best Practices

✅ DO:

  1. DOMContentLoaded nutzen für Scripts im Head
  2. classList statt inline styles
  3. textContent statt innerHTML (wenn möglich)
  4. Event Delegation für viele Elemente
  5. Template Literals für HTML-Strings
Good Practices
// ✅ DOMContentLoaded
document.addEventListener('DOMContentLoaded', () => {
    // Code hier
});

// ✅ classList
element.classList.add('active');

// ✅ textContent (sicher)
element.textContent = userInput;

// ✅ Event Delegation
list.addEventListener('click', (e) => {
    if (e.target.matches('.item')) {
        // Handle click
    }
});

// ✅ Template Literal
const html = `
    <div class="card">
        <h3>${title}</h3>
        <p>${text}</p>
    </div>
`;

❌ DON'T:

  1. Nicht innerHTML mit User-Input (XSS!)
  2. Nicht zu viele Event Listener
  3. Nicht inline Event Handlers (onclick="...")
  4. Nicht document.write() (veraltet)
Anti-Patterns
// ❌ SCHLECHT: XSS-Gefahr
element.innerHTML = userInput;

// ✅ BESSER: textContent
element.textContent = userInput;

// ❌ SCHLECHT: Inline Handler
<button onclick="handleClick()">Click</button>

// ✅ BESSER: addEventListener
button.addEventListener('click', handleClick);

// ❌ SCHLECHT: Zu viele Listener
items.forEach(item => {
    item.addEventListener('click', handler);
});

// ✅ BESSER: Event Delegation
parent.addEventListener('click', (e) => {
    if (e.target.matches('.item')) handler(e);
});

TipsAndTricks

Tipps & Tricks

Event Delegation für bessere Performance

Nutze einen Listener statt vieler:

// ❌ Schlecht: Listener für jedes Element
document.querySelectorAll('.item').forEach(item => {
    item.addEventListener('click', handleClick);
});

// ✅ Gut: Ein Listener auf Parent
document.getElementById('list').addEventListener('click', (e) => {
    if (e.target.classList.contains('item')) {
        handleClick(e);
    }
});
// Funktioniert auch mit dynamisch hinzugefügten Elementen!

classList statt className

Manipuliere Classes elegant:

const element = document.querySelector('.box');

// ❌ Alt: String manipulation
element.className += ' active';
element.className = element.className.replace('active', '');

// ✅ Neu: classList API
element.classList.add('active');
element.classList.remove('inactive');
element.classList.toggle('visible');
element.classList.contains('active');  // true/false

// Mehrere auf einmal
element.classList.add('class1', 'class2', 'class3');

Template Literals für HTML-Generierung

Erstelle dynamischen HTML-Content:

const users = [
    { name: 'Max', age: 25 },
    { name: 'Anna', age: 30 }
];

// Mit Template Literals
const html = users.map(user => `
    <div class="user-card">
        <h3>${user.name}</h3>
        <p>Alter: ${user.age}</p>
    </div>
`).join('');

document.getElementById('container').innerHTML = html;

dataset für Custom Data Attributes

Nutze data-* Attribute für Metadaten:

// HTML: <button data-user-id="123" data-action="delete">
const button = document.querySelector('button');

// Zugriff auf data-*
console.log(button.dataset.userId);    // '123'
console.log(button.dataset.action);    // 'delete'

// Setzen
button.dataset.status = 'active';
// HTML wird: data-status="active"

// CamelCase wird zu kebab-case
button.dataset.userRole = 'admin';
// HTML wird: data-user-role="admin"

📝 Quiz

Was ist der Unterschied zwischen textContent und innerHTML?

📝 Quiz

Warum Event Delegation nutzen?

Übungsaufgaben

Zeit deine DOM-Skills zu testen! Diese Challenges sind etwas anspruchsvoller:

🎯

Aufgabe 1: Element auswählen und ändern

Einfach

Nutze querySelector() um ein Element zu finden und seinen Text zu ändern wenn der Button geklickt wird.

HTML
Live-Vorschau
🎯

Aufgabe 2: classList toggle

Einfach

Erstelle einen Button der eine CSS-Klasse 'active' an/aus schaltet (toggle). Die Klasse macht den Text rot und bold.

HTML
Live-Vorschau
🎯

Aufgabe 3: Live Input Anzeige

Mittel

Zeige in einem <p> Tag live an was der User in das Input-Feld tippt. Nutze das 'input' Event.

HTML
Live-Vorschau
🎯

Aufgabe 4: Element erstellen und hinzufügen

Schwer

Erstelle bei jedem Button-Klick ein neues <li> Element mit Text 'Item X' und füge es zur Liste hinzu.

HTML
Live-Vorschau

Nächste Schritte

Du kennst jetzt:

  • ✅ DOM Struktur & Selectors
  • ✅ Content & Attribute ändern
  • ✅ Styles & Classes
  • ✅ Events & addEventListener
  • ✅ Elemente erstellen/löschen
  • ✅ Praktische Projekte
  • ✅ Event Delegation
  • ✅ Best Practices

Gratulation! Du hast die JavaScript-Grundlagen gemeistert!

Was kommt als Nächstes?

  • Async JavaScript (Promises, async/await)
  • Fetch API (Daten von Server laden)
  • JavaScript Modules
  • Moderne Frameworks (React, Vue, Svelte)

Weiter so! 🚀

JavaScriptLektion 11 von 17
65% abgeschlossen
Lektion abgeschlossen!

Gut gemacht! 🎉

Du hast "JavaScript DOM Manipulation - HTML mit JS ändern" abgeschlossen

Artikel bewerten

0.0 (0 Bewertungen)

Bitte einloggen um zu bewerten