HTML5-Tutorium: JavaScript: Hello World Vue 02

aus GlossarWiki, der Glossar-Datenbank der Fachhochschule Augsburg

Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:

Korrektheit: 3
(zu größeren Teilen überprüft)
Umfang: 4
(unwichtige Fakten fehlen)
Quellenangaben: 3
(wichtige Quellen vorhanden)
Quellenarten: 5
(ausgezeichnet)
Konformität: 3
(gut)

Vorlesung WebProg

Inhalt | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Vue 1 | Vue 2 | Vue 3 | Vue 4 | Vue 5 | Vue 6

Musterlösung
Git-Repository, git checkout v02 (JavaScript)
Git-Repository (TypeScript), git checkout v02

Anwendungsfälle (Use Cases)

Gegenüber dem ersten Teil des Vue-Tutoriums ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.

Aufgabe

Ergänze einen Keyup-Event-Handler, so dass das Name mit Hilfe der Entertaste übergeben werden kann, wenn der Fokus auf dem Namenfeld liegt.

Erstellen eines neuen Projektzweigs

Erstellen Sie einen neuen Projektzweig (branch) innerhalb von hello_world_vue:

git checkout v01     # Wechsle in den Branch v01
git checkout -b v02  # Klone v01 in einen neuen Branch v02
npm i

MVC-Prozess

MVC-Module

Zur Lösung der Aufgabe wird eine eigene Controller-Klasse geschrieben.

Dieser Lösung liegt der MVC-Prozess zu Grunde: Die Anwendung besteht aus Model, Views und Controller.

Das Model enthalt den aktuellen Zustand des Systems in Form von Daten (zum Beispiel die Position und den Radius eines Kreises).

Ein (oder auch mehrere Views) visualisieren Daten aus dem Model. So wird beispielsweise der zuvor genannte Kreis in einem durch den Bildschirm vorgegebenen Koordinatensystem an die im Model gespeicherte Position mit dem passenden Radius gezeichnet. Die View agieren als Observer. Das heißt, sie lauschen auf Änderungen am Model und und aktualisieren sich gegebenenfalls.

Der Benutzer (User) nimmt die Visualisierungen wahr (auch als Observer). Er kann überdies mittels so genannten Controllern mit der Anwendung interagieren. Die Controller reagieren auf Devices wie Maus und Tastatur. Der Benutzer kann mit Hilfe derartiger Devices auch Formulare, die in der View enthalten sind, ausfüllen. Änderungen, die der Benutzer (mit Hilfe von geeigneten Devices) an einer View vornimmt, führen zu Änderungen im Model. Das heißt, die meisten Benutzeraktionen haben schlussendlich Änderungen im Model zur Folge, die dann wieder von der View angezeigt werden.

Es gibt noch eine spezielle Kategorie von Controller-Devices: Force Feedback Controller. Diese reagieren z. B. mittels Vibration auf bestimmte Modelländerungen. Force Feedback Controller sind daher in der Regel bidirektional mit dem Model verknüpft.

ControllerKey: Klasse zum Agieren mit Keyboardevents

Zur Lösung der Aufgabe wird eine eigene Controller-Klasse geschrieben.

Die Aufgabe von Objekten dieser Klasse ist es, auf bestimmte Keyboard-Aktionen des Benutzers hin, sofern sich der HTML-Fokus auf bestimmten HTML-Fomularfeldern befindet, eine Callback-Funktion aufzurufen.

Es wird die Idee aus Aufgabe wk_hello_world_04 (Git-Repository v03), zu diesem Zweck ein eigenes Controller-Modul zu schreiben, wieder aufgegriffen.

class ControllerKey
{ #v_key_events; // private member
  #f_callback;   // private member

  constructor(p_keys, p_callback, p_targets, p_key_events = 'keydown')
  { this.#v_key_events = typeof p_key_events === 'string'
                         ? [p_key_events]
                         : p_key_events;

    const
      c_keys    = typeof p_keys    === 'string' ? [p_keys]    : p_keys,
      c_targets = typeof p_targets === 'string' ? [p_targets] : p_targets

    this.#f_callback =
    p_event =>
    { const
        c_key    = p_event.key,
        c_target = p_event.target.id

      if (c_keys.includes(c_key) && (!c_targets || c_targets.includes(c_target)))
      { // Prevent other handlers from handling the keypress event
        p_event.preventDefault();
        p_event.stopPropagation();
        // Invoke the callback function
        p_callback(c_key, c_target);
      }
    }
  }

  add()
  { for (const l_key_event of this.#v_key_events)
    { window.addEventListener(l_key_event, this.#f_callback) }
  }

  remove()
  { for (const l_key_event of this.#v_key_events)
    { window.removeEventListener(l_key_event, this.#f_callback) }
  }
}

export default ControllerKey

Key-Controller einbinden

Die zuvor definierte Klasse kann nun verwendet werden. Dazu wird sie in HelloWorld.vue importiert.

Dort wird ein neues ControllerKey-Objekt definiert. Dieses wird aktiviert, wenn die Komponenten in eine View eingebunden wird (mounted) wird und deaktiviert, wenn sie wieder entfernt wird (unmounted).

<script setup>
  import { ref, computed, onMounted, onUnmounted } from 'vue'
  import ControllerKey from '@/controller/ControllerKey'

  const
    section       = ref('form'),
    helloStranger = ref('Hello, Stranger'),
    name          = ref(''),

    hello         = computed(() => `Hello, ${name.value}!`),
    visibility    = p_section =>
                    p_section !== section.value ? 'hidden' : '',
    sayHello      = () => section.value = 'hello',
    autofocus     = () => document.getElementById('input_name').focus(),
    controllerKey = new ControllerKey('Enter', sayHello, 'input_name')

  onMounted
  ( () => 
    { window.addEventListener('focus', autofocus);
      controllerKey.add();
      autofocus();
    }
  )

  onUnmounted
  ( () => 
    { window.removeEventListener('focus', autofocus);
      controllerKey.remove();
    }
  )
</script>

Man beachte, dass onMounted und onUnmounted Callback-Funktionen als Eingabeparameter erwarten. Diese werden ausgeführt, sobald die entsprechenden Ereignisse von Vue signalisiert werden.

Simple Variante

In diesem Fall wäre es auch ohne Controller-Klasse gegangen. Und das auch noch einfacher. Man könnte die schon bekannte Funktion sayHelloOnEnter definieren und später mounten.

function sayHelloOnEnter(p_event)
{ if (    p_event.key       === 'Enter'
       && p_event.target.id === 'input_name'
     )
  { // Prevent other handlers from handling the keypress event.
    p_event.preventDefault();
    p_event.stopPropagation();
    sayHello();
  }
}

onMounted  (() => window.addEventListener   ('keydown', sayHelloOnEnter))
onUnmounted(() => window.removeEventListener('keydown', sayHelloOnEnter))

Die Controllerklasse kann jedoch wiederverwendet werden und trennt den Controller sehr schön vom Model. Deshalb ist im Sinne von Bertrand Meyer, die Controllerklassen-Version zu bevorzugen.

Mounting in Vue

Komponenten-Zustände
Vue-Komponenten durchlaufen verschiedene Zustände. Bei jedem Zustandswechsel wird ein Event ausgelöst:

  • beforeCreate: Zustand, bevor eine Komponente initialisiert wird
  • created: Zustand, nachdem eine Komponente vollständig initialisiert wurde
  • beforeMount: Zustand, bevor eine Komponente in den DOM-Baum des Browsers eingefügt wird
  • mounted: Zustand, nachdem eine Komponente in den DOM-Baum des Browsers eingefügt wurde
  • beforeUpdate: Zustand, bevor eine Komponente im DOM-Baum des Browsers modifiziert wird (wegen einer Änderung des zugehörigen Modells)
  • updated: Zustand, nachdem eine Komponente im DOM-Baum des Browsers modifiziert wurde
  • beforeUnmount: Zustand, bevor eine Komponente aus dem DOM-Baum des Browsers gelöscht wird
  • unmounted: Zustand, nachdem eine Komponente aus dem DOM-Baum des Browsers gelöscht wurde

In der Composition API und der Setup-API kann man sich für diese Ereignisse (mit Ausnahme der ersten beiden) als Observer mittels der Methoden

 onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted

registrieren. Daneben gibt es in der Composition API noch ein paar weitere Ereignisse, für die man sich als Observer registrieren kann.==

JSDoc

Wenn wir schon dabei sind, können wir auch gleich noch die JSDoc aktivieren. JSDoc generiert aus gemäß dem JSDoc-Standard kommentierten ECMAScript-/Typescript-Dateien automatisch eine HTML-Dokumentation.

Installieren Sie zunächst JSDOc:

  npm i -D jsdoc
  npm i -D docdash  // oder ein anderes Stylepaket Ihrer Wahl

und erstellen Sie eine zugehörige Konfigurationsdatei:

{ "opts": 
  { "encoding":    "utf8",           
    "destination": "./doc/",         
    "recurse":     true,
    "template":    "node_modules/docdash"
  }
}

Fügen Sie dann den nachfolgenden Befehl in das Objekt scripts der Datei package.json ein:

  "jsdoc": "jsdoc -c .jsdoc.json src"

Wenn Sie nun npm run jsdoc ins Terminal tippen, wird die zugehörige Dokumentation im Ordner doc erzeugt. Diese enthält nur eine Dokumentation für die Datei ControllerKey.js, da dies die einzige Datei ist, die JSDoc-Kommentare enthält.

Fortsetzung des Tutoriums

Sie sollten nun Teil 3 des Vue-Tutoriums bearbeiten. Die Daten werden in einem Store (Model) gespeichert.

Quellen

  1. Kowarschick (WebProg): Wolfgang Kowarschick; Vorlesung „Web-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2024; Quellengüte: 3 (Vorlesung)