Skip to content

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-Code
Live-Vorschau

HTML Wissensquiz

Teste dein Wissen über HTML-Verschachtelung und HTML-Tags.

HTML Wissensquiz

Frage 1 von 6

Welche der folgenden HTML-Strukturen ist korrekt verschachtelt?

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)

HTML-Code
Live-Vorschau

CSS Box Model Quiz

Teste dein Wissen über das CSS Box Model, Margins und Paddings.

Box Model Wissensquiz

Frage 1 von 6

In welcher Reihenfolge (von innen nach außen) sind die Bereiche des Box Models angeordnet?


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)

HTML-Code
Live-Vorschau

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)

HTML-Code
Live-Vorschau

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)

HTML-Code
Live-Vorschau

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)

HTML-Code
Live-Vorschau

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)

HTML-Code
Live-Vorschau

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)

HTML-Code
Live-Vorschau

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:

📄 Vorlage herunterladen

<!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>

Informatik & ICT Unterricht Neufeld