Skip to content
On this page

Vue Commands

Ziel in diesem Versuch ist es, den client der Commands Applikation in VueJS zu implementieren und den Server beizubehalten.

Die umfängliche Dokumentation zu VueJS finden Sie hier https://vuejs.org/guide/quick-start.html.

Hello World Template erstellen

Für folgende Schritte sollten Sie sicherstellen, dass die Volar Extension in VS-Code installiert ist, sowie NodeJS und yarn installiert worden sind.

Vite

Vue ist ein clientseitiges Framework, welches Javascript, HTML und CSS für uns generiert. Unser Source Code wird also neu soft kompiliert, so dass letztendlich aus unserem ganzen Code nur noch ein einziges .js File erstellt wird. Diesen Prozess heisst auch "bundling". Es existieren unterschiedliche Bundler mit ihren Vor- und Nachteilen (webpack, rollup, etc.).

Wir verwenden den Bundler vite.

Erstellen Sie hierzu im web Verzeichnis (welches Sie für die anderen Projekte bereits erstellt haben) ein neues Unterverzeichnis mit dem Namen vue-commands. Öffnen Sie das leere Verzeichnis nun in VS Code.

Im Terminal erstellen Sie nun das VueJS Template mit folgendem Command.

yarn create vite .

Wählen Sie hierbei

  1. Vue
  2. JavaScript

Sie sollten nun einige generierte Files sehen:

Dependencies herunterlanden

Führen Sie nun yarn ohne Argumente aus um die Dependencies herunterzuladen.

Vite erlaubt es Ihnen einen Dev-Server zu starten, welcher die Seite neu generiert, sobald Sie Änderungen am Source vornehmen. Diesen starten Sie mit:

yarn dev

Der Dev Server wird auf dem Port 5173 gestartet. Sie können mit einem CTRL+Click auf die URL die Seite direkt im Browser vom Terminal her öffnen.

Falls alles geklappt hat, werden Sie mit folgender Seite begrüsst:

Vite + Vue Files

Das Template beinhaltet bereits Zahlreiche Files.

  • index.hml ist das Template für die Vue Applikation und beinhaltet den Container für das HTML. Hier können von Hand z.B. Icon und Titel der App geändert werden. Auch können auch falls notwendig zusätzliche Scripts und Styles ausserhalb der Vue App geladen werden.
  • src/main.js ist der Einstiegspunt in welchem Vue geladen wird und wird in der Regel selten geändert.
  • src/styles.css ist das globale Stylesheet, welche für alle Vue Components verwendet wird (Theme). Speziefisches Styling sollte innerhalb der Vue Components stattfinden.
  • src/App.vue ist die Applikation und der Einstiegspunkt um eine Vue App zu erstellen.
  • src/components/ beinhaltet in der Regel Vue Components die in der Applikation modular eingebunden werden.
  • src/assets/ beinhaltet Assets, die on demand geladen werden können.
  • public/ beinhaltet Assets, deren Namen nie geändert werden und die global später unter / verfügbar sein werden (statische Files).

Bundeln der Webseite

Die Webseite kann mit yarn build kompiliert / gebundled werden. Hierbei werden statische Files unter dem Folder dist/ erstellt. Diese können nun irgendwo als statische Webseite gehostet werden. Es handelt sich dabei um eine rein clientseitige Webapplikation.

Warum ein JS Framework?

Wir haben bereits gesehen, dass es möglich ist eine clientseitige Webapplikation mit JS, HTML und CSS zu implementieren. Allerdings sind wir an gewisse strukturen gebunden:

  • Die Seite kann nicht ohne weiteres mit modularen Komponenten erstellt werden.
  • Das Ändern im DOM setzt immer voraus, dass wir mit IDs schaffen um Elemente zu finden. Häufig entfernen wir Elemente und ersetzen diese durch neue.
  • Das CSS ist getrennt von JS und wird im Kontext der ganzen Applikation betrachtet. Es wäre elegant, hätten wir das CSS im Kontext einer Komponente.
  • Reactivity: Ändern wir einen Variable, so wird das UI nicht direkt upgedated um die Änderung zu repräsentieren. In JS Frameworks haben wir häufig reaktive Objekte, die bei einer Änderung ein Update des DOM auslösen.
  • Deklarative Components: Anstelle von <div> wäre es besser eine Component mit Argumenten und Handlern zu haben. <Command name="ls" desc="lists files" @click="remove"/>.

Single File Components (SFC)

Ein Vorteil, welcher Vue gegenüber native JS / HTML bringt, ist das zusammenstellen von Single File Components, die Ähnlich wie bei der OOP zum Ziel haben "separation of concerns" zu erzielen.

Beispiel von https://vuejs.org/guide/introduction.html#single-file-components

vue
<script setup>
import { ref } from 'vue';

const count = ref(0);
</script>

<template>
  <button @click="count++">Count is: {{ count }}</button>
</template>

<style scoped>
button {
  font-weight: bold;
}
</style>

Commands Component

Wir werden für unsere Applikation einige Zeilen von dem Template ersetzen. Löschen Sie hierzu den Inhalt von src/styles.css und das File src/components/HelloWorld.vue.

Ersetzen Sie den Inhalt von src/styles.css mit:

css
body,
html {
  margin: 0;
  padding: 0;
  width: 100%;
  min-height: 100%;
  font-family: sans-serif;
}

body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

Ersetzen Sie den Inhalt von App.vue mit folgendem Code:

vue
<script setup>
import { ref } from "vue";

const commands = ref([
  {
    name: "ls",
    desc: "lists files",
  },
]);

</script>

<template>
  <div class="site">
    <h1>Commands</h1>
    <div class="container">
      <div class="command">
        <div class="name">{{ commands[0].name }}</div>
        <div class="desc">{{ commands[0].desc }}</div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.site {
  padding: 50px 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  max-width: 800px;
  height: 100%;
}

.container {
  width: 200px;
  display: flex;
  flex-wrap: wrap;
}


@media (min-width: 800px) {
  .container {
    width: 400px;
  }
}

@media (min-width: 1000px) {
  .container {
    width: 600px;
  }
}

.command {
  border-radius: 5px;
  display: flex;
  flex-direction: column;
  width: 170px;
  padding: 10px;
  margin: 5px;
  background-color: #555;
  color: #fff;
  cursor: pointer;
}
</style>

Starten Sie den Dev-Server mit yarn dev.

SFC Components und Composition API

App.vue ist in drei Teile unterteilt. <script>, <template> und <style>. App selber ist daher eine SFC (Single File Component).

Variablen, welche in <script setup> deklariert werden, sind in <template> via Mustaches {{ commands[0].name }} verfügbar. ref dient dazu, die Variablen "reactive" zu erstellen. Das heisst, dass Änderungen an deren Werten im UI übernommen werden, ohne dass via getElementById von Hand ein Element gesucht und geändert werden muss.

Schauen Sie sich den ersten Teil der Dokumentation zu Templates an: https://vuejs.org/guide/essentials/template-syntax.html#template-syntax.

Studieren Sie auch den Teil "Reactive Variables with ref()" https://vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive-variables-with-ref

.value

Eine Variable, welche mit ref() erstellt wurde muss immer mit .value gändert werden.

<template> ist das Zuhause für den HTML DOM. Allerdings können hier auch Nicht-HTML Elemente verwendet werden, wie wir später sehen werden. So kann eine zusätzliche Komponente (z.B. <Command>) anstelle von <div> eingefügt werden.

In <style scoped> kann CSS für diese eine Komponente deklariert werden. Das Attribute scoped stellt dabei sicher, dass Selektoren, welche hier eingebettet sind, nicht dem Scope der Komponente verlassen. Das erlaubt das wiederverwenden von gleichen Klassennamen in unterschiedlichen Komponenten.

Listen rendern

Die Applikation ist immer noch rein Clientseitig, wir haben noch keinen Server im betrieb.

Commands ist typischerweise ein Array (welches wir schlussendlich vom Server holen). Ändern Sie den Code nun so, dass das ganze Array gerendert wird in dem Sie sich an folgendem Beitrag orientieren: https://vuejs.org/guide/essentials/list.html#v-for.

Elemente mit Click entfernen

Schauen Sie sich an, wie Sie auf die Commands Elemente einen Click Handler setzen können: https://vuejs.org/guide/essentials/event-handling.html#listening-to-events.

Bauen Sie die App so um, dass ein Element mit einem Click entfernt werden kann.

Tipp: Array filtern

Anstelle, dass Sie tatsächlich Elemente entfernen, können Sie ein neues "gefiltertes" Array erstellen.

Falls Sie nicht sicher sind, wie Sie einen Handler erstellen, finden Sie Dokumentation hier: https://vuejs.org/guide/essentials/event-handling.html#method-handlers

Neue Elemente hinzufügen

In unserer Originalen Applikation hatten wir folgendes Beispiel:

html
<p>Command</p>
<input type="text" id="name" />

<p>Beschreibung</p>
<textarea id="desc"></textarea>

<button id="btn">Neuer Eintrag</button>

Der DOM hatte für name und desc eigene IDs für die entsprechenden Inputs. Bei einem Click haben wir die Elemente gesucht, die Werte extrahiert und ein neues Commands Object erstellt.

Hier ist der Ansatz in Reactive Applikationen bedeutend anders. Was wir in Vue verwenden, sind Variablen, welche als Werte bei <input> und <textarea> gebunden sind.

Lesen Sie den ersten Teil von https://vuejs.org/guide/essentials/forms.html.

  1. Erstellen Sie ein reaktives Objekt currentCommand mit Attributen name und desc.
  2. Erstellen Sie den DOM für die textarea und den text input. Erstellen Sie auch den Button.
  3. Binden Sie die Werte von currentCommand an die Elemente.
  4. Beim Click auf den Button sollen die Werte nun verwendet werden um ein neues Element an commands anzuhängen.

Repo zum nachschlagen

Eine mögliche Lösung finden Sie hier: https://gitlab.fhnw.ch/wlw/vue-commands

Serveranbindung

Binden Sie nun die App an Ihren Commands-Server an. Beachten Sie, dass Sie nicht mehr auf "onload" warten müssen. Sie können direkt in <script> Requests mit fetch ausführen.