Web-Entwicklung Frontend - Aufgaben
Deine erste Webseite - HTML
Erstelle Schritt für Schritt eine vollständige Webseite über ein Thema deiner Wahl (z.B. dein Hobby, ein Lieblingsbuch, ein Tier, eine Stadt, etc.).
Du wirst dabei alle wichtigen HTML-Tags kennenlernen und eine komplette, funktionierende Webseite erstellen!
Konzepte:
- HTML Grundstruktur (
<!DOCTYPE>,<html>,<head>,<body>) - Semantische HTML-Elemente (
<header>,<main>,<footer>,<section>) - Überschriften und Text (
<h1>-<h6>,<p>) - Listen (
<ul>,<ol>,<li>) - Links (
<a>) und Bilder (<img>) - Verschachtelung und Struktur (
<div>,<section>) - Tabellen (
<table>,<tr>,<th>,<td>) - Formulare (
<form>,<input>,<label>,<button>) - Medieneinbettung (
<iframe>) - Barrierefreiheit und Code-Qualität
Schritt für Schritt zur Webseite
Schritt 1 von 13
Schritt 1: HTML Grundstruktur
Erstelle die grundlegende HTML-Struktur mit <!DOCTYPE html>, <html>, <head> und <body>. Füge im <head> einen <title> mit dem Text deiner Wahl hinzu (z.B. "Meine Webseite über...").
Füge auch <meta charset="UTF-8"> und lang="de" zum html-Tag hinzu.
Code-Editor (Schritt für Schritt zur Webseite)
HTML Wissensquiz
Teste dein Wissen über HTML-Verschachtelung und HTML-Tags.
HTML Wissensquiz
Frage 1 von 6
CSS Grundlagen - Einführung
In dieser Aufgabe lernst du die grundlegenden CSS-Konzepte kennen: Selektoren (Klassen, IDs, Element-Selektoren), Farben, Schriftarten, Margins, Paddings und Borders.
Konzepte:
- CSS-Klassen und IDs
- Element-Selektoren und kombinierte Selektoren
- Farbformate (Hex, RGB, RGBA)
- Schriftarten und Text-Styling
- Box Model: Margins, Paddings, Borders
- Border-Radius
CSS Grundlagen Schritt für Schritt
Schritt 1 von 15
Schritt 1: Klassen erstellen und verwenden
Erstelle eine CSS-Klasse .highlight die den Text rot färbt und fett macht. Wende sie auf den ersten Absatz an.
Code-Editor (CSS Grundlagen Schritt für Schritt)
CSS Box Model Quiz
Teste dein Wissen über das CSS Box Model, Margins und Paddings.
Box Model Wissensquiz
Frage 1 von 6
CSS Backgrounds
Lerne, wie du mit CSS ansprechende Hintergründe gestaltest - von einfachen Farben über Gradients bis zu Hintergrundbildern.
Konzepte:
- Hintergrundfarben (einfach und transparent)
- Lineare und radiale Gradients
- Hintergrundbilder
- Background-Size und Background-Position
- Kombination von Gradient und Bild
Backgrounds gestalten
Schritt 1 von 8
Schritt 1: Einfache Hintergrundfarbe
Gib dem .box1 Element eine hellblaue Hintergrundfarbe (#e3f2fd) und füge etwas Padding (20px) hinzu, damit der Hintergrund sichtbar ist.
Code-Editor (Backgrounds gestalten)
Bilder stylen und ausrichten
Lerne, wie du Bilder responsive machst, zentrierst und mit verschiedenen Effekten versiehst.
Konzepte:
- Responsive Bilder
- Bilder zentrieren
- Border-Radius und Box-Shadow
- Kreisförmige Bilder
- Object-fit für Bildanpassung
Bilder professionell stylen
Schritt 1 von 5
Schritt 1: Responsive Bildbreite
Style das erste Bild (.img-responsive) so, dass es maximal 600px breit ist, aber auf kleineren Bildschirmen schmaler wird. Die Höhe soll automatisch angepasst werden.
Code-Editor (Bilder professionell stylen)
Flexbox Layouts
Flexbox ist eines der wichtigsten Layout-Systeme in modernem CSS. Lerne, wie du flexible, responsive Layouts erstellst.
Konzepte:
- Flex-Container und Flex-Items
- Justify-Content (horizontale Ausrichtung)
- Align-Items (vertikale Ausrichtung)
- Flex-Direction und Flex-Wrap
- Gap zwischen Items
- Flex-Grow und Flex-Basis
- Praktische Navigation mit Flexbox
Flexbox Layouts meistern
Schritt 1 von 10
Schritt 1: Flex-Container erstellen
Mache .flex-container zu einem Flex-Container. Beobachte, wie die Items sich nebeneinander anordnen.
Code-Editor (Flexbox Layouts meistern)
CSS Transitions und Hover-Effekte
Lerne, wie du mit CSS Transitions sanfte Animationen und ansprechende Hover-Effekte erstellst.
Konzepte:
- Einfache Transitions (Farbe, Größe)
- Transform (Scale, Translate)
- Kombinierte Effekte
- Box-Shadow Transitions
- Opacity Fade-Effekte
- Timing-Functions
Interaktive Hover-Effekte
Schritt 1 von 5
Schritt 1: Einfacher Hover-Effekt auf Farbe
Erstelle für .btn-color einen Button, der bei Hover die Hintergrundfarbe von blau (#3498db) zu dunkelblau (#2980b9) wechselt. Die Transition soll 0.3s dauern.
Code-Editor (Interaktive Hover-Effekte)
JavaScript TODO-App
Erstelle eine vollständige, funktionale TODO-App mit Vanilla JavaScript! Du lernst dabei die Grundlagen der DOM-Manipulation, Event Handling und wie man interaktive Webseiten erstellt.
Diese Aufgabe kombiniert HTML, CSS und JavaScript - du wirst eine echte Anwendung bauen, die du verwenden kannst!
Konzepte:
- DOM-Manipulation (
getElementById,createElement,appendChild) - Event Listener (
addEventListener,click,keypress) - Dynamische Elemente erstellen und entfernen
- CSS-Styling für interaktive Elemente
- Flexbox Layout
- Transitions und Hover-Effekte
- User Input verarbeiten
- Zustandsänderungen (erledigt/nicht erledigt)
Was die App können wird:
- TODOs hinzufügen (per Button oder Enter-Taste)
- TODOs als erledigt markieren (durchgestrichen)
- TODOs löschen
- Leere Eingaben abfangen
- Professionelles Design mit Schatten und Animationen
TODO-App mit JavaScript
Schritt 1 von 21
Schritt 1: HTML Grundstruktur erstellen
Erstelle die HTML-Struktur der TODO-App: Ein Container-Div mit Überschrift, Input-Feld, Button und eine Liste für die TODOs.
Code-Editor (TODO-App mit JavaScript)
Vue.js TODO-App
Erstelle die gleiche TODO-App wie zuvor, aber diesmal mit Vue.js! Du wirst sehen, wie viel einfacher und übersichtlicher der Code mit einem Framework wird.
Vue.js kümmert sich automatisch um die DOM-Manipulation - du musst nur die Daten ändern, und Vue aktualisiert die Ansicht automatisch!
Vorbereitung: Kopiere zuerst das Vue.js Template aus dem Vue.js Script in den Code-Editor unten, bevor du mit den Schritten beginnst.
Konzepte:
- Vue-App Setup (
createApp,mount) - Reaktive Daten (
data()) - Two-Way Data Binding (
v-model) - Event Handling (
@click,@keyup.enter) - List Rendering (
v-for) - Conditional Rendering (
v-if) - Methods für Logik
- Dynamic Classes (
:class)
Was die App können wird:
- TODOs hinzufügen mit v-model binding
- TODOs als erledigt markieren
- TODOs löschen
- Gleiche Funktionalität wie die Vanilla-JS Version, aber mit weniger Code!
TODO-App mit Vue.js
Schritt 1 von 17
Schritt 1: HTML-Struktur erstellen
Das Vue.js Template sollte bereits kopiert sein. Erstelle nun im <div id="app"> die HTML-Struktur: Überschrift, Input-Feld, Button und eine leere Liste.
Code-Editor (TODO-App mit Vue.js)
Vue.js Repetition
Kopiere den folgenden Code in eine neue Datei in deinem Editor und bearbeite die darin beschriebenen Aufgaben:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue.js Übung – Mein Lerntagebuch</title>
<!-- Vue 3 via CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Georgia, serif;
background: #f5f0e8;
color: #2c2c2c;
padding: 2rem;
min-height: 100vh;
}
h1 {
font-size: 2rem;
margin-bottom: 0.25rem;
letter-spacing: -0.5px;
}
h2 {
font-size: 1.1rem;
font-weight: normal;
color: #666;
margin-bottom: 2rem;
font-style: italic;
}
#app {
max-width: 600px;
margin: 0 auto;
}
.karte {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 2px 2px 0 #ddd;
}
.karte h3 {
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 1px;
color: #999;
margin-bottom: 1rem;
}
.profil-info {
font-size: 1.1rem;
margin-bottom: 0.5rem;
}
.fortschritt-balken {
height: 10px;
background: #eee;
border-radius: 10px;
margin-top: 0.5rem;
overflow: hidden;
}
.fortschritt-fill {
height: 100%;
background: #3a7bd5;
border-radius: 10px;
transition: width 0.4s ease;
}
.badge {
display: inline-block;
background: #e8f0fe;
color: #3a7bd5;
border-radius: 20px;
padding: 0.2rem 0.75rem;
font-size: 0.85rem;
margin-top: 0.5rem;
}
button {
background: #2c2c2c;
color: white;
border: none;
padding: 0.6rem 1.2rem;
border-radius: 6px;
cursor: pointer;
font-size: 0.95rem;
font-family: inherit;
margin-top: 0.5rem;
}
button:hover {
background: #3a7bd5;
}
input[type="text"] {
width: 100%;
padding: 0.5rem;
font-size: 1rem;
font-family: inherit;
border: 1px solid #ccc;
border-radius: 6px;
margin-top: 0.5rem;
}
.notiz-liste {
list-style: none;
margin-top: 1rem;
}
.notiz-liste li {
padding: 0.5rem 0;
border-bottom: 1px solid #eee;
font-size: 0.95rem;
}
.notiz-liste li:last-child {
border-bottom: none;
}
.modul-liste {
list-style: none;
}
.modul-liste li {
padding: 0.4rem 0;
display: flex;
justify-content: space-between;
font-size: 0.95rem;
border-bottom: 1px solid #f0f0f0;
}
.modul-status {
font-size: 0.8rem;
color: #3a7bd5;
font-style: italic;
}
.versteckt-box {
margin-top: 1rem;
background: #f0f7ff;
border-left: 3px solid #3a7bd5;
padding: 0.75rem 1rem;
border-radius: 0 6px 6px 0;
font-style: italic;
color: #444;
}
/* =====================
AUFGABEN-KOMMENTARE
Alle Aufgaben sind als Kommentare direkt
im HTML-Template markiert (siehe unten).
===================== */
</style>
</head>
<body>
<div id="app">
<h1>📓 {{ titel }}</h1>
<h2>{{ untertitel }}</h2>
<!-- ============================================================
AUFGABE 1 – Daten-Objekt (String, Zahl, Objekt)
============================================================
Das Vue-App-Objekt hat bereits einen "titel" und "untertitel".
Füge im data()-Objekt (unten im <script>) folgende Felder hinzu:
- name: "Dein Name" → ein String
- kurs: "Frontend Dev" → ein String
- fortschritt: 40 → eine Zahl (Prozent, 0–100)
- profil: { → ein Objekt
stufe: "Anfänger",
punkte: 120
}
Zeige dann folgende Werte in der Karte unten an, indem du
die Mustache-Syntax {{ }} verwendest:
name, kurs, profil.stufe, profil.punkte
Beispiel-Syntax:
<p>{{ name }}</p>
<p>{{ profil.stufe }}</p>
============================================================ -->
<div class="karte">
<h3>Mein Profil</h3>
<!-- AUFGABE 1: Zeige name, kurs, profil.stufe, profil.punkte hier an -->
<p class="profil-info">Name: </p>
<p class="profil-info">Kurs: </p>
<p class="profil-info">Stufe: </p>
<p class="profil-info">Punkte: </p>
<!-- AUFGABE 1 (Bonus): Zeige den Fortschrittsbalken an.
Setze die width des .fortschritt-fill Divs auf fortschritt + "%"
(das kommt in Aufgabe 3 mit v-bind, lass es hier noch leer) -->
<div class="fortschritt-balken">
<div class="fortschritt-fill" style="width: 0%"></div>
</div>
<p style="font-size:0.85rem; color:#888; margin-top:0.3rem">Fortschritt: (Fortschritt als Zahl anzeigen)</p>
</div>
<!-- ============================================================
AUFGABE 2 – v-on: Click-Event
============================================================
Füge im data()-Objekt folgende Felder hinzu:
- punkte: 0 (oder verwende profil.punkte aus Aufgabe 1)
Füge im methods-Objekt eine Methode "punkteHinzufuegen" hinzu,
die bei jedem Klick 10 Punkte addiert.
Binde die Methode mit v-on:click (oder @click) an den Button.
Beispiel-Syntax:
<button v-on:click="macheEtwas()">Klick mich</button>
oder kurz:
<button @click="macheEtwas()">Klick mich</button>
methods: {
macheEtwas() {
this.wert = this.wert + 1
}
}
============================================================ -->
<div class="karte">
<h3>Tagesaufgabe</h3>
<p>Klicke den Button, um 10 Punkte zu verdienen.</p>
<!-- AUFGABE 2: v-on:click an diesen Button binden -->
<button>+10 Punkte verdienen</button>
<!-- AUFGABE 2: Zeige den aktuellen Punkte-Stand hier an -->
<p style="margin-top:0.75rem">Deine Punkte: <!-- {{ profil.punkte }} --></p>
</div>
<!-- ============================================================
AUFGABE 3 – v-bind: Attribut-Binding
============================================================
v-bind erlaubt es, HTML-Attribute dynamisch an Vue-Daten zu binden.
Beispiel-Syntax:
<div v-bind:style="{ width: fortschritt + '%' }"></div>
oder kurz:
<div :style="{ width: fortschritt + '%' }"></div>
<img :src="bildUrl" :alt="bildBeschreibung">
AUFGABE 3a: Gehe zurück zu Aufgabe 1 (Fortschrittsbalken) und
binde die width des .fortschritt-fill Divs dynamisch an "fortschritt":
:style="{ width: fortschritt + '%' }"
AUFGABE 3b: Füge im data()-Objekt ein Feld hinzu:
- tipp: "Du lernst Vue – das ist grossartig!"
Binde das "title"-Attribut des Badge-Elements unten an dieses Feld,
sodass beim Hovern über das Badge dein Tipp erscheint.
============================================================ -->
<div class="karte">
<h3>Mein Abzeichen</h3>
<!-- AUFGABE 3b: :title an "tipp" binden -->
<span class="badge">⭐ Lernender</span>
<p style="font-size:0.8rem; color:#888; margin-top:0.5rem">
(Hover über das Abzeichen für einen Tipp)
</p>
</div>
<!-- ============================================================
AUFGABE 4 – v-if: Bedingung
============================================================
v-if zeigt ein Element nur an, wenn die Bedingung true ist.
Beispiel-Syntax:
<p v-if="punkte > 100">Du hast über 100 Punkte!</p>
<p v-else>Noch nicht genug Punkte.</p>
AUFGABE 4: Füge im data()-Objekt ein Feld hinzu:
- motivationSichtbar: false
Füge einen Button hinzu, der beim Klick "motivationSichtbar"
auf true/false umschaltet (toggle).
Zeige den Motivations-Text unten nur an, wenn motivationSichtbar === true.
Bonus: Zeige einen alternativen Text an mit v-else.
============================================================ -->
<div class="karte">
<h3>Motivation</h3>
<!-- AUFGABE 4: Button zum Umschalten -->
<button>Motivation anzeigen / verstecken</button>
<!-- AUFGABE 4: Diesen Block nur anzeigen wenn motivationSichtbar true ist -->
<div class="versteckt-box">
💡 "Der einzige Weg, gute Arbeit zu machen, ist, das zu lieben, was man tut."
</div>
<!-- AUFGABE 4 (Bonus): v-else Text wenn motivationSichtbar false ist -->
</div>
<!-- ============================================================
AUFGABE 5 – v-for: Schleife + v-model: Two-Way Binding
============================================================
v-for rendert eine Liste von Elementen aus einem Array.
v-model verbindet ein input-Feld direkt mit einem data-Feld.
Beispiel-Syntax (v-for):
<li v-for="item in liste" :key="item">{{ item }}</li>
Beispiel-Syntax (v-model):
<input v-model="neuerText" type="text">
<!-- neuerText wird automatisch aktualisiert beim Tippen -->
AUFGABE 5a: Füge im data()-Objekt folgende Felder hinzu:
- module: [ → ein Array von Objekten
{ name: "HTML & CSS", abgeschlossen: true },
{ name: "JavaScript Grundlagen", abgeschlossen: true },
{ name: "Vue.js Einführung", abgeschlossen: false },
{ name: "Komponenten & Props", abgeschlossen: false }
]
- neueNotiz: "" → ein leerer String für das Input-Feld
- notizen: [] → leeres Array für gespeicherte Notizen
AUFGABE 5b: Rendere die Module-Liste mit v-for.
Zeige bei abgeschlossenen Modulen ein ✓ an.
AUFGABE 5c: Binde das Input-Feld mit v-model an "neueNotiz".
Füge einen Button hinzu, der "neueNotiz" zum "notizen"-Array hinzufügt
und das Feld danach leert.
Zeige die Notizen-Liste mit v-for an.
Hinweis: Array erweitern geht so:
this.notizen.push(this.neueNotiz)
============================================================ -->
<div class="karte">
<h3>Kursmodule</h3>
<!-- AUFGABE 5b: Module hier mit v-for rendern -->
<ul class="modul-liste">
<!-- Beispiel (entfernen wenn fertig):
<li v-for="modul in module" :key="modul.name">
{{ modul.name }}
<span class="modul-status" v-if="modul.abgeschlossen">✓ Fertig</span>
</li>
-->
<li><em>Module erscheinen hier nach Aufgabe 5...</em></li>
</ul>
</div>
<div class="karte">
<h3>Meine Notizen</h3>
<!-- AUFGABE 5c: Input mit v-model binden -->
<input type="text" placeholder="Neue Notiz eingeben..." />
<!-- AUFGABE 5c: Button zum Speichern der Notiz -->
<button>Notiz speichern</button>
<!-- AUFGABE 5c: Notizen-Liste mit v-for rendern -->
<ul class="notiz-liste">
<!-- Beispiel:
<li v-for="(notiz, index) in notizen" :key="index">{{ notiz }}</li>
-->
<li><em>Noch keine Notizen...</em></li>
</ul>
</div>
</div><!-- Ende #app -->
<script>
const { createApp } = Vue
createApp({
data() {
return {
// Bereits vorhanden – nicht ändern:
titel: "Mein Lerntagebuch",
untertitel: "Vue.js Einführungsübung",
// ============================================================
// AUFGABE 1: Füge hier deine Felder hinzu:
// name, kurs, fortschritt, profil (Objekt mit stufe & punkte)
// ============================================================
// ============================================================
// AUFGABE 2: (punkte sind Teil von profil – bereits erledigt
// wenn Aufgabe 1 fertig ist)
// ============================================================
// ============================================================
// AUFGABE 3: Füge hier "tipp" hinzu
// ============================================================
// ============================================================
// AUFGABE 4: Füge hier "motivationSichtbar" hinzu
// ============================================================
// ============================================================
// AUFGABE 5: Füge hier "module", "neueNotiz", "notizen" hinzu
// ============================================================
}
},
methods: {
// ============================================================
// AUFGABE 2: Füge hier "punkteHinzufuegen()" hinzu
// ============================================================
// ============================================================
// AUFGABE 4: Füge hier "motivationUmschalten()" hinzu
// ============================================================
// ============================================================
// AUFGABE 5: Füge hier "notizSpeichern()" hinzu
// ============================================================
}
}).mount('#app')
</script>Vue.js Übung – Mein Haustier-Simulator
Bearbeite die Aufgaben in der folgenden Vorlagendatei:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue.js Übung – Mein Haustier-Simulator</title>
<!-- Vue 3 via CDN -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
color: #333;
padding: 2rem;
min-height: 100vh;
}
h1 {
color: white;
text-align: center;
margin-bottom: 0.5rem;
font-size: 2.2rem;
}
.untertitel {
color: #a8c0ff;
text-align: center;
margin-bottom: 2rem;
font-size: 1.1rem;
}
#app {
max-width: 700px;
margin: 0 auto;
}
.info-karte {
background: white;
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
.info-karte h2 {
font-size: 1.2rem;
color: #1e3c72;
margin-bottom: 1rem;
border-bottom: 2px solid #eee;
padding-bottom: 0.5rem;
}
.stat-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
text-align: center;
}
.stat-box {
background: #f8f9fa;
padding: 1rem;
border-radius: 8px;
}
.stat-zahl {
font-size: 1.8rem;
font-weight: bold;
color: #2a5298;
}
.stat-label {
font-size: 0.85rem;
color: #666;
}
.pet-liste {
list-style: none;
}
.pet-karte {
background: #f8f9fa;
border-radius: 10px;
padding: 1rem;
margin-bottom: 0.75rem;
display: flex;
justify-content: space-between;
align-items: center;
border-left: 4px solid #2a5298;
transition: transform 0.2s;
}
.pet-karte:hover {
transform: translateX(5px);
}
.pet-info h3 {
font-size: 1.1rem;
color: #333;
}
.pet-info p {
font-size: 0.9rem;
color: #666;
}
.pet-status {
display: flex;
align-items: center;
gap: 0.5rem;
}
.badge {
padding: 0.3rem 0.7rem;
border-radius: 20px;
font-size: 0.8rem;
font-weight: bold;
}
.badge-hunger {
background: #fee;
color: #c00;
}
.badge-satt {
background: #efe;
color: #080;
}
.badge-glücklich {
background: #ffe0b2;
color: #e65100;
}
button {
background: #2a5298;
color: white;
border: none;
padding: 0.6rem 1.2rem;
border-radius: 6px;
cursor: pointer;
font-size: 0.95rem;
transition: background 0.2s;
}
button:hover {
background: #1e3c72;
}
button.futter-btn {
background: #4caf50;
padding: 0.4rem 0.8rem;
font-size: 0.85rem;
}
button.futter-btn:hover {
background: #388e3c;
}
button.delete-btn {
background: #f44336;
padding: 0.4rem 0.8rem;
font-size: 0.85rem;
}
button.delete-btn:hover {
background: #d32f2f;
}
input[type="text"], input[type="number"] {
padding: 0.5rem;
font-size: 1rem;
border: 1px solid #ddd;
border-radius: 6px;
margin-right: 0.5rem;
}
input[type="text"] {
width: 150px;
}
select {
padding: 0.5rem;
font-size: 1rem;
border: 1px solid #ddd;
border-radius: 6px;
margin-right: 0.5rem;
background: white;
}
.filter-buttons {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.filter-buttons button {
background: #e0e0e0;
color: #333;
}
.filter-buttons button.active {
background: #2a5298;
color: white;
}
.filter-buttons button:hover:not(.active) {
background: #bdbdbd;
}
.aktion-buttons {
display: flex;
gap: 0.5rem;
}
.form-row {
display: flex;
align-items: center;
margin-bottom: 0.5rem;
}
.form-row label {
display: inline-block;
width: 80px;
font-size: 0.9rem;
color: #666;
}
.leer-text {
text-align: center;
color: #999;
font-style: italic;
padding: 2rem;
}
.message {
background: #e8f5e9;
color: #2e7d32;
padding: 0.75rem;
border-radius: 6px;
margin-bottom: 1rem;
text-align: center;
}
/* =====================
AUFGABEN-KOMMENTARE
Alle Aufgaben sind als Kommentare direkt
im HTML-Template markiert (siehe unten).
===================== */
</style>
</head>
<body>
<div id="app">
<h1>🐾 {{ titel }}</h1>
<p class="untertitel">{{ untertitel }}</p>
<!-- ============================================================
AUFGABE 1 – Daten-Objekt (Array von Objekten)
============================================================
Das Vue-App-Objekt hat bereits "titel" und "untertitel".
Füge im data()-Objekt (unten im <script>) folgende Felder hinzu:
- tiere: [ → ein Array von Objekten
{ name: "Buddy", art: "Hund", hunger: 30, stimmung: "glücklich" },
{ name: "Mittens", art: "Katze", hunger: 70, stimmung: "neutral" },
{ name: "Hoppel", art: "Kaninchen", hunger: 80, stimmung: "hungerig" }
]
- filter: "alle" → String für aktuellen Filter
Zeige dann in der Liste unten alle Tiere mit v-for an.
Verwende {{ tiere.length }} für die Gesamtzahl.
Hinweis: Denk daran, dass du Arrays mit der gleichen Syntax
wie Objekte ansprichst: tiere[0].name gibt "Buddy" zurück.
============================================================ -->
<div class="info-karte">
<h2>📊 Statistiken</h2>
<div class="stat-grid">
<div class="stat-box">
<!-- AUFGABE 1: Zeige die Anzahl der Tiere hier an -->
<div class="stat-zahl">0</div>
<div class="stat-label">Tiere gesamt</div>
</div>
<div class="stat-box">
<!-- AUFGABE 2: Zeige die Anzahl der hungrigen Tiere hier an -->
<div class="stat-zahl">0</div>
<div class="stat-label">Hungrige Tiere</div>
</div>
<div class="stat-box">
<!-- AUFGABE 3: Berechne und zeige den Durchschnitt der Hunger-Werte -->
<div class="stat-zahl">0</div>
<div class="stat-label">Ø Hunger</div>
</div>
</div>
</div>
<!-- ============================================================
AUFGABE 2 – Methoden mit for-Schleife
============================================================
Aufgabe 1 ist fertig, wenn du die Tiere in der Liste siehst.
AUFGABE 2a: Füge im data()-Objekt ein Feld hinzu:
- hungrigeTiereCount: 0
AUFGABE 2b: Erstelle eine Methode "zaehleHungrige()", die mit einer
for-Schleife durch das tiere-Array geht und zählt, wie viele
Tiere hunger >= 50 haben.
Der Aufruf soll automatisch beim Start passieren.
Nutze created() { this.zaehleHungrige() }
Beispiel for-Schleife:
for (let i = 0; i < array.length; i++) {
// array[i] ist das aktuelle Element
}
AUFGABE 2c: Rufe die Methode auch immer auf, wenn sich die
Tierliste ändert (nach Füttern oder Löschen).
============================================================ -->
<!-- ============================================================
AUFGABE 3 – Durchschnitt berechnen
============================================================
AUFGABE 3a: Erstelle eine Methode "berechneDurchschnitt()",
die den durchschnittlichen Hunger-Wert berechnet.
Gehe mit einer for-Schleife durch alle Tiere:
1. Summiere alle hunger-Werte auf
2. Teile die Summe durch die Anzahl der Tiere
3. Runde das Ergebnis mit Math.round()
Tipp: Wenn es keine Tiere gibt, gib 0 zurück (Division durch 0 verhindern).
Beispiel:
let summe = 0;
for (let i = 0; i < this.tiere.length; i++) {
summe = summe + this.tiere[i].hunger;
}
let durchschnitt = summe / this.tiere.length;
============================================================ -->
<div class="info-karte">
<h2>🔍 Filter</h2>
<div class="filter-buttons">
<!-- AUFGABE 4: Füge Filter-Buttons hinzu mit @click -->
<button class="active">Alle</button>
<button>Hungerig</button>
<button>Satt</button>
</div>
<!-- AUFGABE 4: Die Liste soll jetzt nur die gefilterten Tiere zeigen -->
<ul class="pet-liste">
<!-- AUFGABE 1 & 4: Tiere hier mit v-for rendern -->
<li class="pet-karte">
<div class="pet-info">
<h3>Beispiel-Tier</h3>
<p>Art: -</p>
</div>
<div class="pet-status">
<span class="badge badge-satt">Satt</span>
</div>
</li>
</ul>
</div>
<!-- ============================================================
AUFGABE 4 – v-if / v-else und Filter-Logik
============================================================
AUFGABE 4a: Erstelle eine berechnete Eigenschaft (computed)
"gefilterteTiere" – sie soll das Array filtern basierend auf
dem filter-Wert:
- "alle": alle Tiere zurückgeben
- "hungerig": nur Tiere mit hunger >= 50
- "satt": nur Tiere mit hunger < 50
AUFGABE 4b: Ersetze das einfache v-for oben durch:
<li v-for="tier in gefilterteTiere" ...>
AUFGABE 4c: Füge @click an die Filter-Buttons, die den
filter-Wert setzen (this.filter = "alle", etc.)
AUFGABE 4d: Nutze v-bind:class um den aktiven Button
hervorzuheben: :class="{ active: filter === 'alle' }"
Hinweis zu computed Properties:
computed: {
gefilterteTiere() {
if (this.filter === "alle") {
return this.tiere;
} else if (this.filter === "hungerig") {
// Schleife oder filter() verwenden
}
// ...
}
}
============================================================ -->
<!-- ============================================================
AUFGABE 5 – Event-Handling und Array-Manipulation
============================================================
AUFGABE 5a: Füge im data()-Objekt ein Feld hinzu:
- neueTierName: ""
- neueTierArt: "Hund"
AUFGABE 5b: Erstelle eine Methode "tierHinzufuegen()":
- Erstelle ein neues Tier-Objekt mit name, art, hunger=30, stimmung="glücklich"
- Füge es mit this.tiere.push(neuesTier) zum Array hinzu
- Leere das Eingabefeld wieder
AUFGABE 5c: Binde das Input-Feld mit v-model an "neueTierName"
und den select mit v-model an "neueTierArt"
AUFGABE 5d: Binde den Button mit @click="tierHinzufuegen"
AUFGABE 5e: Rufe nach dem Hinzufügen zaehleHungrige() und
berechneDurchschnitt() auf, um die Stats zu aktualisieren.
Hinweis: push() fügt ein Element am Ende des Arrays hinzu.
============================================================ -->
<div class="info-karte">
<h2>➕ Neues Tier hinzufügen</h2>
<div class="form-row">
<label>Name:</label>
<!-- AUFGABE 5: v-model hier hinzufügen -->
<input type="text" placeholder="Name eingeben..." />
</div>
<div class="form-row">
<label>Tierart:</label>
<!-- AUFGABE 5: v-model hier hinzufügen -->
<select>
<option value="Hund">Hund</option>
<option value="Katze">Katze</option>
<option value="Kaninchen">Kaninchen</option>
<option value="Hamster">Hamster</option>
<option value="Vogel">Vogel</option>
</select>
</div>
<!-- AUFGABE 5: @click hier hinzufügen -->
<button>Tier hinzufügen</button>
</div>
<!-- ============================================================
AUFGABE 6 – Element finden und ändern
============================================================
AUFGABE 6a: Erstelle eine Methode "tierFuettern(tier)":
- Verringere den hunger-Wert um 20 (aber nicht unter 0)
- Setze stimmung auf "glücklich"
- Aktualisiere die Statistiken
Tipp: tier.hunger = Math.max(0, tier.hunger - 20)
AUFGABE 6b: Binde die Methode an den "Füttern" Button
in der Tierliste: @click="tierFuettern(tier)"
AUFGABE 6c: Ändere die stimmung auf "satt" wenn hunger < 30
============================================================ -->
<!-- Die Tier-Liste von oben sollte jetzt diese Buttons haben:
<button class="futter-btn" @click="tierFuettern(tier)">🍖 Füttern</button>
-->
<!-- ============================================================
AUFGABE 7 – Element finden und löschen
============================================================
AUFGABE 7a: Erstelle eine Methode "tierLoeschen(index)":
- Entferne das Tier aus dem Array mit splice(index, 1)
- splice(start, anzahl) entfernt Elemente
- WICHTIG: Da wir mit gefilterter Liste arbeiten, müssen wir
den echten Index im Original-Array finden!
Tipp: So findest du den Index im Original-Array:
const echterIndex = this.tiere.indexOf(tier);
this.tiere.splice(echterIndex, 1);
AUFGABE 7b: Binde an den "Löschen" Button:
@click="tierLoeschen(tier)"
AUFGABE 7c: Aktualisiere die Statistiken nach dem Löschen.
============================================================ -->
<!-- Die Tier-Liste von oben sollte jetzt diesen Button haben:
<button class="delete-btn" @click="tierLoeschen(tier)">🗑️</button>
-->
<!-- ============================================================
AUFGABE 8 – Optional: Das glücklichste Tier finden
============================================================
Erstelle eine Methode "findeGluecklichstesTier()":
- Gehe mit einer for-Schleife durch alle Tiere
- Finde das Tier mit der niedrigsten hunger-Zahl
- Gib den Namen zurück oder "Keine Tiere" wenn leer
Zeige das Ergebnis in einer info-karte an.
Hinweis: Du brauchst eine Variable für das glücklichste Tier
und update sie in der Schleife, wenn du ein noch glücklicheres findest.
============================================================ -->
</div><!-- Ende #app -->
<script>
const { createApp } = Vue
createApp({
data() {
return {
// Bereits vorhanden – nicht ändern:
titel: "Mein Haustier-Simulator",
untertitel: "Vue.js Übung – Pflege deine virtuellen Haustiere!",
// ============================================================
// AUFGABE 1: Füge hier "tiere" (Array) und "filter" hinzu
// ============================================================
// ============================================================
// AUFGABE 2: Füge hier "hungrigeTiereCount" hinzu
// ============================================================
// ============================================================
// AUFGABE 5: Füge hier "neueTierName" und "neueTierArt" hinzu
// ============================================================
}
},
created() {
// ============================================================
// AUFGABE 2: Rufe hier zaehleHungrige() auf
// ============================================================
},
computed: {
// ============================================================
// AUFGABE 4: Füge hier "gefilterteTiere" hinzu
// ============================================================
// ============================================================
// AUFGABE 3: Optional – Durchschnitt als computed Property
// ============================================================
},
methods: {
// ============================================================
// AUFGABE 2: Füge hier "zaehleHungrige()" hinzu
// ============================================================
// ============================================================
// AUFGABE 3: Füge hier "berechneDurchschnitt()" hinzu
// ============================================================
// ============================================================
// AUFGABE 5: Füge hier "ufuegen()"tierHinz hinzu
// ============================================================
// ============================================================
// AUFGABE 6: Füge hier "tierFuettern(tier)" hinzu
// ============================================================
// ============================================================
// AUFGABE 7: Füge hier "tierLoeschen(tier)" hinzu
// ============================================================
// ============================================================
// AUFGABE 8: Optional: "findeGluecklichstesTier()"
// ============================================================
}
}).mount('#app')
</script>
</body>
</html>