Dieses Tutorial richtet sich an Entwickler, die AJAX praxisnah lernen wollen. Am Ende wirst du ein funktionierendes Highscore-System haben, das Benutzer dynamisch einträgt, anzeigt und die Datenbank verwendet, ohne die Seite neu zu laden.
1. Projektidee und Vorbereitung
Wir wollen ein Highscore-Board für ein Spiel bauen. Funktionen:
- Spieler kann seinen Namen und Punkte eintragen.
- Highscores werden dynamisch angezeigt.
- Es gibt eine Datenbank zur Speicherung.
- Alles passiert asynchron, ohne Seitenreload.
- Benutzerfreundliches Design (Buttons, Feedback, Ladeindikatoren).
Vorbereitung:
- Webserver mit PHP (z. B. XAMPP, MAMP, LAMP)
- Datenbank (MySQL oder SQLite)
- Browser mit Developer Tools (Console & Network)
2. Datenbankdesign
Bevor wir AJAX einsetzen, müssen wir verstehen, welche Daten wir speichern:
- Tabelle: highscores
- Spalten:
- id (Primärschlüssel)
- username (Spielername)
- score (Punkte)
- timestamp (Zeitpunkt des Eintrags)
Warum?
- Wir brauchen einen Ort, um Daten zu persistieren.
- Timestamp hilft bei Sortierung und Verwaltung.
Best Practice: Index auf score setzen für schnelle Sortierung.
3. HTML-Struktur
Das Frontend muss Elemente haben, die wir dynamisch aktualisieren:
- Eingabefelder für Name und Punkte
- Button zum Absenden
- Bereich für Highscore-Liste
- Ladeanzeige oder Feedback
Wichtig:
- Jeder Bereich sollte eine eindeutige ID oder Klasse haben.
- So kann JavaScript gezielt Inhalte aktualisieren.
Konzept: HTML dient nur als Container. Die Logik wird über AJAX gesteuert.
4. AJAX-Konzept verstehen
AJAX ermöglicht asynchrone Anfragen:
- Request: Browser fragt den Server nach Daten.
- Response: Server liefert Daten zurück (JSON ist Standard).
- Update: JavaScript aktualisiert die Seite dynamisch.
Flow:
- Nutzer klickt auf „Highscore speichern“.
- JS sammelt Daten (Name, Punkte).
- AJAX-Request wird an PHP-Skript geschickt.
- PHP speichert Daten in Datenbank.
- PHP sendet Response (Erfolg, Fehler).
- JS zeigt Rückmeldung und lädt aktualisierte Highscore-Liste.
5. Server-Seite (PHP)
Der Server muss Requests entgegennehmen und verarbeiten:
- Eingaben validieren (Sicherheit)
- Highscore speichern
- Highscore abrufen
- Fehler sauber zurückgeben
Best Practices:
- Prepared Statements gegen SQL-Injection.
- Sanitizing: HTML/JS-Sonderzeichen entfernen.
- Response immer JSON: Einfaches Parsen im Frontend.
6. Frontend-Logik (JavaScript)
Aufgaben:
- Daten sammeln und senden
- AJAX-Request erstellen
- Response verarbeiten
- UI aktualisieren (Highscore-Liste, Feedback)
Wichtige Konzepte:
- EventListener für Button-Klick
- Fetch API oder XMLHttpRequest
- Promise Handling für asynchrone Abläufe
- Error Handling: Netzwerkprobleme, Serverfehler
Tipp: Ladeanzeige zeigen, solange Server antwortet, sonst wirkt die Seite „statisch“.
7. Dynamische Highscore-Liste
Highscores müssen nach jedem Eintrag aktualisiert werden, ohne Reload:
- AJAX holt aktuelle Top10-Scores vom Server.
- JS leert die bestehende Liste.
- JS baut neue Listenelemente und fügt sie ein.
Best Practices:
- Liste in <ul> oder <table> einfügen.
- Bei vielen Einträgen Pagination oder Limit einbauen.
- Optional: Animation beim Aktualisieren.
8. Sicherheitsaspekte
AJAX allein macht das Frontend nicht sicher:
- Input-Validation: Immer serverseitig prüfen.
- Rate-Limiting: Spam verhindern, z. B. nur 1 Eintrag pro 10 Sekunden pro IP.
- Captcha: Optional, um Bots zu blockieren.
- Prepared Statements: Verhindern SQL-Injection.
Frontend-Sicherheiten können umgangen werden, Server ist die letzte Schutzebene.
9. Erweiterungsmöglichkeiten
- E-Mail Bestätigung: Spielername + Score nur nach E-Mail-Verifikation speichern.
- Benutzerkonten: Highscore pro Account speichern.
- Live-Update: WebSocket oder regelmäßiges AJAX-Refresh.
- PWA: Mobile Installation, offline Anzeige der Highscores.
10. Fazit und Zusammenfassung
Mit AJAX:
- Webseiten fühlen sich flüssig an.
- Nutzerinteraktionen erfolgen sofort.
- Datenbankinteraktionen sind asynchron, was die UX verbessert.
- Konzepte wie EventListener, Fetch API und JSON sind zentral.
Wer AJAX versteht, kann klassische Webseiten in interaktive Web-Apps verwandeln.
Der nächste Schritt ist, die Kombination aus AJAX, PHP und Datenbank zu meistern und eigene dynamische Webprojekte zu bauen.
Das sehe dann so aus:
<?php
// Highscore Demo
session_start();
// SQLite-Datenbank erstellen oder verbinden
$db = new PDO('sqlite:'.__DIR__.'/highscores.db');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->exec("CREATE TABLE IF NOT EXISTS highscores (
id INTEGER PRIMARY KEY,
username TEXT,
score INTEGER,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)");
// Highscore speichern
if(isset($_POST['action']) && $_POST['action'] === 'save_score'){
$username = htmlspecialchars($_POST['username']);
$score = intval($_POST['score']);
if($username && $score>=0){
$stmt = $db->prepare("INSERT INTO highscores (username, score) VALUES (?, ?)");
$stmt->execute([$username, $score]);
echo json_encode(['success'=>true]);
} else {
echo json_encode(['success'=>false,'error'=>'Ungültige Daten']);
}
exit;
}
// Highscores abrufen
if(isset($_GET['action']) && $_GET['action'] === 'get_scores'){
$stmt = $db->query("SELECT username, score FROM highscores ORDER BY score DESC LIMIT 10");
$scores = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($scores);
exit;
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Highscore AJAX Demo</title>
<style>
body{margin:0;font-family:sans-serif;background:#111;color:#eee;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;min-height:100vh;}
header{padding:20px;text-align:center;font-size:2em;color:#ffcc00;}
#game-area{margin:20px auto;text-align:center;}
input, button{padding:8px 12px;margin:5px;border:none;border-radius:4px;}
input{width:200px;}
button{background:#ffcc00;color:#111;font-weight:bold;cursor:pointer;}
#feedback{margin-top:10px;color:#ff6666;}
#highscores{margin-top:20px;width:300px;text-align:left;}
#highscores ul{list-style:none;padding:0;}
#highscores li{padding:5px;border-bottom:1px solid #333;}
footer{margin-top:auto;padding:10px;color:#888;text-align:center;}
</style>
</head>
<body>
<header>Highscore AJAX Demo</header>
<div id="game-area">
<input type="text" id="username" placeholder="Dein Name">
<input type="number" id="score" placeholder="Punkte">
<button id="saveScore">Highscore speichern</button>
<div id="feedback"></div>
</div>
<div id="highscores">
<h3>Top 10 Highscores</h3>
<ul id="scoreList"></ul>
</div>
<footer>© <?=date('Y')?> <a href="http://www.dreamcodes.net" target="_blank">Dreamcodes</a> — Highscore Demo</footer>
<script>
// Funktion zum Laden der Highscores
function loadScores(){
fetch('?action=get_scores')
.then(response => response.json())
.then(data => {
const list = document.getElementById('scoreList');
list.innerHTML = '';
data.forEach(s => {
const li = document.createElement('li');
li.textContent = `${s.username}: ${s.score}`;
list.appendChild(li);
});
});
}
// Highscore speichern
document.getElementById('saveScore').addEventListener('click', ()=>{
const username = document.getElementById('username').value.trim();
const score = parseInt(document.getElementById('score').value.trim());
const feedback = document.getElementById('feedback');
if(!username || isNaN(score)){
feedback.textContent = 'Bitte Name und Punkte korrekt eingeben!';
return;
}
feedback.textContent = 'Speichern...';
fetch('',{
method:'POST',
headers:{'Content-Type':'application/x-www-form-urlencoded'},
body:`action=save_score&username=${encodeURIComponent(username)}&score=${score}`
})
.then(r=>r.json())
.then(res=>{
if(res.success){
feedback.style.color = '#00ff00';
feedback.textContent = 'Highscore gespeichert!';
document.getElementById('username').value = '';
document.getElementById('score').value = '';
loadScores();
} else {
feedback.style.color = '#ff6666';
feedback.textContent = res.error || 'Fehler beim Speichern';
}
})
.catch(()=>feedback.textContent='Serverfehler');
});
// Initial Highscores laden
loadScores();
</script>
</body>
</html>