Skip to content

TODO-App Musterlösung (Vue.js)

Dies ist die vollständige Musterlösung für die TODO-App mit Vue.js.

Verwendung

  1. Kopiere den gesamten Code unten
  2. Erstelle eine neue HTML-Datei (z.B. todo-app-vue.html)
  3. Füge den Code ein und speichere die Datei
  4. Öffne die Datei in deinem Browser

Code

html
<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>TODO App - Vue.js</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
      background-color: #f5f5f5;
      padding: 20px;
    }

    .container {
      max-width: 500px;
      margin: 50px auto;
      background: white;
      padding: 30px;
      border-radius: 10px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    }

    h1 {
      color: #333;
      text-align: center;
      margin-bottom: 30px;
      font-size: 32px;
    }

    input[type="text"] {
      width: 100%;
      padding: 12px;
      border: 2px solid #ddd;
      border-radius: 5px;
      font-size: 16px;
      transition: border-color 0.3s, box-shadow 0.3s;
    }

    input[type="text"]:focus {
      outline: none;
      border-color: #4CAF50;
      box-shadow: 0 0 5px rgba(76, 175, 80, 0.5);
    }

    button {
      width: 100%;
      background-color: #4CAF50;
      color: white;
      font-size: 16px;
      padding: 12px;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      margin-top: 15px;
      transition: background-color 0.2s;
    }

    button:hover {
      background-color: #45a049;
    }

    ul {
      list-style: none;
      padding: 0;
      margin-top: 20px;
    }

    .todo-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      background-color: #f9f9f9;
      padding: 12px 15px;
      margin-bottom: 10px;
      border-radius: 5px;
      border: 1px solid #ddd;
      transition: all 0.3s ease;
    }

    .todo-item:hover {
      transform: translateX(5px);
      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
    }

    .todo-item span {
      flex: 1;
      transition: all 0.3s;
    }

    .completed {
      text-decoration: line-through;
      color: #888;
    }

    .complete-btn,
    .delete-btn {
      padding: 5px 10px;
      border: none;
      border-radius: 3px;
      cursor: pointer;
      margin-left: 5px;
      width: auto;
      margin-top: 0;
      transition: background-color 0.2s;
    }

    .complete-btn {
      background-color: #4CAF50;
      color: white;
    }

    .complete-btn:hover {
      background-color: #45a049;
    }

    .complete-btn:disabled {
      background-color: #ccc;
      cursor: not-allowed;
    }

    .delete-btn {
      background-color: #f44336;
      color: white;
    }

    .delete-btn:hover {
      background-color: #da190b;
    }

    .empty-message {
      text-align: center;
      color: #999;
      margin-top: 20px;
    }
  </style>
</head>
<body>
  <div id="app" class="container">
    <h1>Meine TODO-Liste</h1>
    <input
      type="text"
      v-model="todoInput"
      @keyup.enter="addTodo"
      placeholder="Neue Aufgabe eingeben...">
      <button @click="addTodo">Hinzufügen {{todoInput}}</button>

    <p v-if="todos.length === 0" class="empty-message">
      Keine Aufgaben vorhanden. Füge eine neue hinzu!
    </p>

    <ul v-else>
      <li v-for="(todo, index) in todos" :key="index" class="todo-item">
        <span :class="{ completed: todo.completed }">{{ todo.text }}</span>
        <button
          class="complete-btn"
          @click="completeTodo(index)"
          :disabled="todo.completed">

        </button>
        <button class="delete-btn" @click="deleteTodo(index)">✗</button>
      </li>
    </ul>
  </div>

  <script type="module">
    import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'

    createApp({
      data() {
        return {
          todoInput: '',
          todos: [
            {text: "Hallo Welt", completed: false}
          ]
        }
      },
      methods: {
        addTodo() {
          // Input-Wert prüfen
          if (this.todoInput.trim() === '') {
            alert('Bitte Aufgabe eingeben!');
            return;
          }

          // TODO zum Array hinzufügen
          this.todos.push(
            {
            text: this.todoInput,
            completed: false
          }
          );

          // Input leeren
          this.todoInput = '';
        },

        deleteTodo(index) {
          // TODO aus Array entfernen
          this.todos.splice(index, 1);
        },

        completeTodo(index) {
          // TODO als erledigt markieren
          this.todos[index].completed = true;
        }
      }
    }).mount('#app')
  </script>
</body>
</html>

Erklärung

Diese Vue.js Lösung zeigt die wichtigsten Vue-Konzepte:

  • Reaktive Daten: todoInput und todos Array im data() Bereich
  • Two-Way Binding: v-model für automatische Synchronisation zwischen Input und Daten
  • Event Handling: @click und @keyup.enter für Benutzerinteraktionen
  • List Rendering: v-for zum automatischen Rendern der TODO-Liste
  • Conditional Rendering: v-if und v-else für die leere Nachrichten-Anzeige
  • Dynamic Classes: :class für das durchgestrichene Styling
  • Methods: Alle Logik sauber in Methoden organisiert

Vorteile gegenüber Vanilla JavaScript

  • Weniger Code: Vue übernimmt die DOM-Manipulation automatisch
  • Deklarativ: Du beschreibst, WAS angezeigt werden soll, nicht WIE
  • Reaktivität: Änderungen an Daten aktualisieren die UI automatisch
  • Bessere Organisation: Daten, Methoden und Template sind klar getrennt

Zurück zu den Aufgaben

Informatik & ICT Unterricht Neufeld