Wie man eine App baut: To-dos mit feinem Unterschied

JavaScript Frameworks im Vergleich: Vue vs. Angular vs. React
2 Kommentare

Vue.js, Angular oder React? Wer ein Projekt beginnt, steht vor der Qual der Wahl. Vue.js wird immer beliebter, die Community wächst. Im direkten Vergleich zu Angular und React lässt sich gut zeigen, wann die Library die richtige Wahl ist.

Vue, Angular oder React? Die Qual der Wahl!

Schenkt man der Auswertung über JavaScript-Frameworks von npm Glauben, liegt Vue.js mittlerweile auf Platz drei der beliebtesten Frameworks. Doch wesentlich interessanter als der absolute Anteil an den Downloadzahlen ist vielmehr das Wachstum. Sehen Sie sich diesen Teil der Auswertung an, wird schnell klar, dass Sie von Vue.js in der nächsten Zeit noch mehr hören werden. Vue.js wächst aktuell deutlich stärker als die anderen betrachteten Frameworks, und das nicht ohne Grund. Vue.js ist, ähnlich wie React, ein Framework, das sich auf die Darstellung konzentriert und nicht wie Angular das komplette Frontend einer Applikation abdeckt.

Das macht Vue.js zu einem leichtgewichtigen und flexiblen Werkzeug in der Entwicklung. Hinzu kommt, dass Vue.js im Vergleich zu React oder Angular relativ einfach zu erlernen ist. Auch die Community, die sich um das Framework gebildet hat, trägt ihren Teil zu dessen steigender Beliebtheit bei, indem immer mehr Werkzeuge und Erweiterungen für das Framework umgesetzt werden. Im Laufe dieses Artikels werde ich Ihnen einige Gemeinsamkeiten, aber auch Unterschiede zwischen Angular, React und Vue.js zeigen, sodass Sie sich selbst ein Bild von dem Framework machen und seine Einsatzgebiete einschätzen können.

 

Installation und erste Schritte

Vue.js ist ein Open-Source-Framework, das vollständig auf GitHub entwickelt wird. Das Framework selbst und zahlreiche Hilfsmittel und Erweiterungen finden Sie dort. Außerdem existieren für alle benötigten Komponenten Pakete auf npm beziehungsweise Yarn. Die einfachste Variante, mit Vue.js zu arbeiten, besteht allerdings darin, die JavaScript-Datei des Pakets direkt im Browser einzubinden und das Vue.js-Objekt global zu verwenden. Das ist vergleichbar mit der Art, auf die jQuery benutzt wird. Dieser Ansatz wird jedoch nur für sehr kleine Applikationen empfohlen, daher gehen wir darauf nicht weiter ein. Allerdings teilen sich diese globale Vue-Instanz und die im Folgenden verwendeten Components den gleichen Aufbau, sodass Sie die in diesem Artikel beschriebenen Features auch dort einsetzen können.

Um mit der Entwicklung einer Vue.js-Applikation zu beginnen, sollten Sie zunächst das Vue-CLI installieren. Der Einsatz von Kommandozeilenwerkzeugen zum Scaffolding einer Applikation hat sich mittlerweile bei allen großen Frameworks als Standard durchgesetzt. Das Vue-CLI bereitet die Grundlagen Ihrer Applikation so vor, dass Sie anschließend sofort mit der Entwicklung beginnen können. Eine mit dem CLI aufgesetzte Applikation enthält außerdem einen Dev-Server, der ähnlich funktioniert wie in Angular oder React, wenn Sie die Applikationen mit dem jeweiligen CLI initialisieren. Das Vue.js-CLI wird mit dem Kommando npm install -g @vue/cli global auf Ihrem System installiert, sodass Ihnen das vue-Kommando auf der Konsole des Systems zur Verfügung steht. Mit dem Kommando vue create todo-list lassen Sie die Struktur Ihres Projekts per CLI erzeugen.

In der dritten Version des CLI werden Sie durch einen interaktiven Prozess geleitet, an dessen Ende eine funktionstüchtige Applikation steht. Sie können hier das Preset, also die verwendeten Werkzeuge wie Babel und eslint, auswählen und den zu verwendenden Package-Manager angeben. Für den Anfang reicht hier die Standardauswahl aus, die Sie erhalten, indem Sie beide Fragen mit der Eingabetaste bestätigen. Nachdem Sie Ihre Auswahl getroffen haben, werden sämtliche Abhängigkeiten heruntergeladen und die Verzeichnisstruktur wird erzeugt. Im Anschluss wechseln Sie in das erzeugte Verzeichnis und führen das Kommando npm run serve aus. Das sorgt dafür, dass der Dev-Server gestartet wird und Ihnen die Applikation unter http://localhost:8081 zur Verfügung stellt.

Die generierte Struktur enthält auf der obersten Ebene das Verzeichnis node_modules, in dem sich die installierten Abhängigkeiten befinden, ein Verzeichnis mit dem Namen public, in dem das Favicon und die HTML-Datei liegen, die als Einstieg in die Applikation dient, und schließlich das src-Verzeichnis, in dem Sie den Quellcode Ihrer Applikation ablegen werden. Neben diesen Verzeichnissen finden sich eine vorbereitete .gitignore-Datei, die package.json mit der Beschreibung der Applikation sowie die package-lock.json, die den installierten Abhängigkeitsbaum mit allen Versionen und Integritäts-Hashes enthält.

Zur Entwicklung Ihrer Applikation empfehle ich Ihnen die Verwendung einer IDE mit Vue.js-Support, zum Beispiel Visual Studio Code mit dem Vetur-Plug-in oder WebStorm mit seiner integrierten Vue.js-Unterstützung.

Kostenlos: Das iJS React Cheat Sheet

Sie wollen mit React durchstarten?
Unser Cheatsheet zeigt Ihnen alle wichtigen Snippets auf einen Blick.
Jetzt kostenlos herunterladen!

Download for free

 

API Summit 2018

From Bad to Good – OpenID Connect/OAuth

mit Daniel Wagner (VERBUND) und Anton Kalcik (business.software.engineering)

Komponenten in Vue.js

Werfen Sie nun einen Blick in das src-Verzeichnis Ihrer Applikation, sehen Sie hier bereits zwei Dateien. Die Datei main.js ist für den Start Ihrer Applikation verantwortlich. Hier wird die zentrale Vue.js-Instanz Ihrer Applikation erzeugt und die App-Komponente gerendert. Diese Komponente befindet sich in der Datei App.vue und stellt den zentralen Einstiegspunkt dar. Hier kommen Sie zum ersten Mal mit einer sogenannten Single-File Component in Berührung. Diese Components haben laut Konvention die Dateiendung .vue und beinhalten alle erforderlichen Teile einer Komponente.

Sämtliche Vue.js-Komponenten teilen sich den gleichen grundlegenden Aufbau, der den Regeln der Vue. js-Instanz folgt. Eine Komponente ist zunächst also nichts weiter als eine Vue.js-Instanz. Vue.js-Komponenten können sowohl über Vue.component als auch als Single-File Components erzeugt werden. Das Problem an der Erzeugung von Komponenten mit Vue.component ist, dass sie global verfügbar sind und es so zu Namenskonflikten kommen kann, sodass die Single-File Components die bessere Wahl sind. Eine solche Komponente besteht aus drei Teilen: einem Template, dem JavaScript-Code der Komponente und einem Stylesheet.

Anzeige von Informationen

Der JavaScript-Anteil der Komponente spielt die Rolle des ViewModels. Das bedeutet, dass sie der View in Form des Templates die Daten zur Verfügung stellt. Innerhalb des Script-Tags wird ein Objekt exportiert, das zumindest die name-Eigenschaft aufweist, die den Namen der Komponente angibt, sowie die data-Eigenschaft. Über diese Eigenschaft gelangen dynamische Inhalte in die Komponente. Listing 1 enthält den Quellcode der Komponente.

<script>
  export default {
    name: 'TodoList',
    data() {
      return {todos: [
        {id: 1, title: 'Get up', done: true},
        {id: 2, title: 'Eat', done: true},
        {id: 3, title: 'Sleep', done: false},
      ]};
    }
  }
</script>

Hinter der data-Eigenschaft verbirgt sich eine Methode, die das Datenobjekt zurückliefert. Die Daten aus diesem Beispiel stellen eine einfache Variante einer Todo-Liste dar. Jeder Eintrag besitzt eine ID, einen Titel sowie den Status der Aufgabe.

Die data-Eigenschaft ist am besten mit den Properties der Komponentenklasse in Angular und dem State einer React-Komponente vergleichbar. Alle drei Konstrukte stellen dem Template die Informationen zur Verfügung. In Listing 2 sehen Sie das zugehörige Template der Vue. js-Komponente, die dafür verantwortlich ist, die Liste anzuzeigen.

<template>
  <ul>
    <li v-for="todo in todos" v-bind:key="todo.id">
      {{todo.title}}
    </li>
  </ul>
</template>

Der dynamische Zugriff aus dem Template auf Eigenschaften des Komponentenobjekts und deren Anzeige wird als Interpolation bezeichnet. Auch dieses Konzept ist aus Angular und React bekannt. Angular nutzt, wie auch Vue.js, die doppelten geschweiften Klammern, die ursprünglich aus der Mustache-Template-Engine stammen. React hingegen arbeitet mit einzelnen geschweiften Klammern. Für die Darstellung benötigen Sie im Template neben der Interpolation noch eine sogenannte Direktive. Direktiven sind HTML-Attribute, die Vue. js dazu veranlassen, die DOM-Struktur anzupassen. Mit einer v-for-Direktive iterieren Sie über die todos-Eigenschaft, die aus der data-Eigenschaft der Komponente stammt. Die Anweisung todo in todos erzeugt eine lokale Variable, die in der folgenden Interpolation verwendet werden kann. Entwicklern von Angular-Applikationen wird dieses Konstrukt bekannt vorkommen. Mit der ngFor-Direktive gibt es dort eine Entsprechung. Mit dem v-bind:key-Attribut helfen Sie Vue.js, den Zustand der Komponente besser verwalten zu können. Die Eigenschaft, die Sie hier verwenden, sollte in ihrem Wert in der Iteration eindeutig sein.

Konditionales Rendering in Vue.js

Momentan wird dem Benutzer lediglich der Titel der einzelnen Aufgaben in einer einfachen Listenansicht angezeigt. Interessant ist jedoch auch der Status der jeweiligen Aufgabe. Dieser liegt in Form der Eigenschaft done als Boolean-Wert vor. Solche Werte können Sie für das konditionale Rendering in Vue.js verwenden. Das bedeutet, dass bestimmte Teilbäume des DOM nur gerendert werden, wenn eine bestimmte Bedingung eintritt. In Listing 3 kommen die v-if– und v-else-Direktiven zum Einsatz, um abhängig vom Status der Aufgabe entweder einen Haken oder ein Kreuz anzuzeigen.

<template>
  <ul>
    <li v-for="todo in todos" v-bind:key="todo.id">
      {{todo.title}}
      <span v-if="todo.done">✔</span>
      <span v-else>✘</span>
    </li>
  </ul>
</template>

Umgang mit Events

Eine Applikation wie eine To-do-Liste lebt von der Interaktion des Benutzers mit der Anwendung. Außerdem verfehlt eine To-do-Liste ihren Zweck, wenn man Aufgaben nicht als erledigt markieren kann. Also müssen Sie im nächsten Schritt die Möglichkeit schaffen, dass ein Benutzer mit der Applikation arbeiten kann. Im einfachsten Fall ist eine solche Interaktion über Klick-Events möglich. Um einen solchen Event Handler zu registrieren, verfügt Vue.js über die v-on-Direktive. Dieser folgt dann der Typ des Events, durch einen Doppelpunkt getrennt. In unserem Fall führt dies dann zu einem Attributnamen von v-on:click. Da dieser relativ häufig zum Einsatz kommt, haben die Entwickler mit @click eine Abkürzung dafür geschaffen. Beide Varianten sind in ihrer Funktionsweise gleichwertig. Der Direktive übergeben Sie als Wert eine Methode der Komponente, die als Event Handler dienen soll. Listing 4 zeigt Ihnen, wie Sie die Statusänderung im Template vorbereiten können.

<template>
  <ul>
    <li v-for="todo in todos" v-bind:key="todo.id">
      {{todo.title}}
      <span v-if="todo.done" v-on:click="toggleState()">✔</span>
      <span v-else @click="toggleState()">✘</span>
    </li>
  </ul>
</template>

Zur Einbindung solcher Event Handler stehen mehrere Möglichkeiten zur Wahl. Es ist möglich, nur den Namen des Handlers anzugeben. Dann wird die Funktion mit einer Objektrepräsentation des Events aufgerufen. Geben Sie, wie im Beispiel, Parameter im Template an, werden diese an den Event Handler übergeben. Sollten Sie in diesem Fall ebenfalls an Details zum Event interessiert sein, können Sie eine Objektrepräsentation des Events mithilfe der Variable $event an den Handler übergeben. Die Implementierung des Event Handlers findet in der Komponente statt, genauer gesagt innerhalb der methods-Eigenschaft. Diese beinhaltet eine Objektstruktur, die die konkreten Handler-Funktionen als Methoden zur Verfügung stellt. In Listing 5 sehen Sie die Umsetzung am konkreten Beispiel der Statusänderung.

<script>
  export default {
    name: 'TodoList',
    data() {
      return {todos: []};
    },
    methods: {
      toggleState(id) {
        const index = this.todos.findIndex((todo) => todo.id === id);
        const todo = this.todos[index];
        todo.done = !todo.done;
      },
    }
  }
</script>

Die Komponente wird von Vue.js verarbeitet. So ist es möglich, aus der toggleState-Methode heraus über this auf die Eigenschaften der Komponente zuzugreifen. So können Sie, wie im Beispiel, auf die todos-Eigenschaft zugreifen und diese entsprechend anpassen. Die konkrete Änderung findet statt, indem Sie die Array-Methode findIndex nutzen, um den Index der übergebenen Aufgabe herauszufinden und den Zustand zu ändern. Durch den reaktiven Charakter von Vue.js wird die Änderung in die View zurücksynchronisiert, sodass der Benutzer sofort eine visuelle Rückmeldung über die Statusänderung erhält.

In Abbildung 1 sehen Sie den aktuellen Stand Ihrer Applikation. Wie Sie sehen, sieht das Resultat momentan noch eher mäßig aus. Das lässt sich jedoch mit etwas CSS leicht beheben.

Styling in Vue.js

Abb.1: Der aktuelle Stand der Anwendung

Abb.1: Der aktuelle Stand der Anwendung

In einer komponentenbasierten Applikation ist das Styling stets ein Problem. Das liegt vor allem daran, dass das Styling in der Regel nichts von den Komponenten weiß und so die Style-Angaben entweder für die komplette Applikation gelten oder erst mühevoll mit Namespaces versehen werden müssen. Vue.js verfolgt beim Thema Styling einen ähnlichen Ansatz wie Angular, indem es für jede Komponente ein eigenes Stylesheet vorsieht. Damit dieses lokale Styling funktionieren kann, müssen Sie das scoped-Attribut in das Style-Tag der Komponente einfügen. Dieses Attribut sorgt dafür, dass die Styling-Regeln nur auf die Elemente der aktuellen Komponente angewendet werden. Fehlt dieses Attribut, gelten die Styles für die gesamte Applikation. Um die Aufgabenliste etwas ansehnlicher zu gestalten, können Sie das Stylesheet in Listing 6 für Ihre Komponente anwenden.

<style scoped>
  ul {
    list-style: none;
    padding-left: 0;
    width: 400px;
    margin: 0 auto;
  }
  li {
    line-height: 30px;
    border: 1px solid darkgray;
    padding: 10px;
    margin: 2px 0;
    position: relative;
  }
  span {
    position: absolute;
    right: 10px;
  }
</style>

Um erledigte und noch offene Aufgaben grafisch etwas besser hervorzuheben, lässt sich der Hintergrund des jeweiligen Eintrags entsprechend rot oder grün einfärben. Die Schwierigkeit hierbei liegt darin, dass der Style abhängig von den angezeigten Informationen ist. Zur Lösung dieses Problems können Sie entweder eine Klasse verwenden, die mit einem passenden Style verbunden ist oder inline-Styles nutzen. Mit dem v-bind-Attribut haben Sie die Möglichkeit, dynamisch CSS-Klassen zuzuweisen. In Listing 7 sehen Sie den erforderlichen Quellcode.

<template>
  <ul>
    <li v-for="todo in todos" v-bind:key="todo.id"
        v-bind:class="todo.done ? 'done' : 'open'">
      {{todo.title}}
      <span v-if="todo.done" v-on:click="toggleState()">✔</span>
      <span v-else @click="toggleState()">✘</span>
    </li>
  </ul>
</template>
…
<style scoped>
…
  .done {
    background-color: lightgreen;
  }

  .open {
    background-color: lightsalmon;
  }
</style>

Die hier gezeigte Variante sorgt dafür, dass dem li-Element die Klasse done zugewiesen wird, falls die done-Eigenschaft der Aufgabe den Wert true aufweist. Ist das nicht der Fall, wird false zugewiesen. Auch hier wirkt sich eine Statusänderung eines Eintrags direkt auf das Styling aus. Wenn Sie also auf einen Eintrag klicken, um ihn als erledigt zu markieren, ändert sich nicht nur das Symbol, sondern auch die Hintergrundfarbe. Für die Zuweisung von Klassen gibt es zwei weitere Optionen: Sie können die Klassen eines HTML-Elements entweder als Objekt oder als Array angeben. Bei der Objektnotation stehen die Eigenschaftsnamen für die jeweiligen Klassennamen, und der Wert legt fest, ob das Element die Klasse erhalten soll oder nicht. Bei der Array-Notation werden die einzelnen Elemente als Eigenschaften des data-Objekts der Komponente interpretiert.

Ähnlich wie bei den Klassen können Sie auch bei einzelnen Styles vorgehen und diese Elementen direkt zuweisen. Hier haben Sie eine weitere dynamische und noch feinere Steuerungsmöglichkeit über das Aussehen einzelner Elemente. Hierfür verwenden Sie das Attribut v-bind:style und können wiederum die Objekt- oder Array-Notation verwenden.

Kindkomponenten

Der große Vorteil eines Frameworks wie Vue.js ist, dass Sie Ihre Applikation in eine Vielzahl von Komponenten aufteilen können, die wiederum eine Baumstruktur bilden. Diesen Architekturansatz können Sie auch in der To-do-Liste verfolgen. Aktuell wird die Applikation von nur einer Komponente gebildet. Die List-Komponente lässt sich jedoch in eine Rahmenkomponente und eine weitere Komponente für die Darstellung der einzelnen Listeneinträge unterteilen. Hierfür lagern Sie die li-Einträge der Liste in eine eigene Komponente mit dem Namen TodoListItem aus. Diese liegt in einer Datei mit dem Namen TodoListItem.vue im components-Verzeichnis.

Die Datei weist den gleichen dreiteiligen Aufbau wie schon die TodoList auf, ist also in ein Template, einen Script-Teil und ein Stylesheet unterteilt. Da Sie lediglich Funktionalität aus der TodoList-Komponente auslagern und keine neue Funktionalität hinzufügen, existiert ein Großteil des Quellcodes der Kindkomponente bereits. In Listing 8 finden Sie den Quellcode der Komponente.

<template<
  <li v-bind:class="todo.done ? 'done' : 'open'"<
      {{todo.title}}
      <span v-if="todo.done" v-on:click="toggleState(todo.id)"<✔</span<
      <span v-else @click="toggleState(todo.id)"<✘</span<
    </li<
</template<

<script<
  export default {
    props: ['todo'],
  }
</script<

<style scoped<
  li {
    line-height: 30px;
    border: 1px solid darkgray;
    padding: 10px;
    margin: 2px 0;
    position: relative;
  }
  span {
    position: absolute;
    right: 10px;
  }

  .done {
    background-color: lightgreen;
  }

  .open {
    background-color: lightsalmon;
  }
</style<

Die TodoListItem-Komponente kümmert sich um sämtliche Aufgaben, die für die Anzeige eines einzelnen Listeneintrags erforderlich sind. Die Iteration fällt beispielsweise nicht darunter. Die passende Hintergrundfarbe für die Listeneinträge liegt jedoch im Verantwortungsbereich der Kindkomponente (Abb. 2). In der ersten Ausbaustufe verfügt die Kindkomponente noch über keinerlei Funktionalität.

Abb. 2: Die Darstellung der Kindkomponente

Abb. 2: Die Darstellung der Kindkomponente

Props – Datenfluss von der Elternkomponente zur Kindkomponente

Zunächst müssen Sie sich um die korrekte Darstellung kümmern. Dazu muss die Kindkomponente die Informationen über den darzustellenden Datensatz von der Elternkomponente erhalten. Das geschieht über einen Mechanismus, der bei Angular Input-Binding und bei React Props heißt. Auch in Vue.js werden Informationen, die von der Eltern- an die Kindkomponente weitergereicht werden, als Props bezeichnet. Damit dieser Mechanismus funktioniert, müssen Sie die verfügbaren Props in der Kindkomponente in der props-Eigenschaft in Form eines Arrays definieren. In der Elternkomponente übergeben Sie die Informationen mithilfe der v-bind-Direktive. Im Fall der todo-Prop werden die Informationen mittels v-bind:todo übergeben. Da v-bind in einer Vue.js-Applikation relativ häufig verwendet wird, gibt es dafür eine verkürzte Schreibweise, ähnlich wie bei v-on. Statt also v-bind:todo zu schreiben, können Sie auch die Kurzform :todo im Template verwenden. Bevor Sie nun jedoch zur eigentlichen Einbindung der TodoListItem-Komponente übergehen können, müssen Sie sie zuerst registrieren und damit Vue.js die Komponente bekannt machen. Zunächst importieren Sie die Kindkomponente und fügen dann einen entsprechenden Eintrag in die components-Eigenschaft der Elternkomponente ein. Listing 9 enthält sowohl die Einbindung in das Template als auch die Registrierung.

<template>
  <ul>
    <TodoListItem v-for="todo in todos" v-bind:todo="todo" 
     v-bind:key="todo.id"></TodoListItem>
  </ul>
</template>

<script>
  import TodoListItem from './TodoListItem';

  export default {
    components: {
      TodoListItem
    },
…

Wechseln Sie nun in Ihren Browser, sehen Sie oberflächlich keinerlei Änderungen, mit der Ausnahme, dass das Erledigen der einzelnen Aufgaben noch nicht funktioniert. Ein weiteres wichtiges Detail verbirgt sich in der DOM-Struktur der Applikation. Öffnen Sie die Entwicklerwerkzeuge Ihres Browsers, sehen Sie, dass die TodoListItem-Tags nicht gerendert werden. Das bedeutet, dass Sie trotz der Komponentenorientierung von Vue.js gültiges HTML erzeugen lassen können.

Events – umgekehrter Datenfluss

Nun, da Sie wissen, wie die Kommunikation von Elternzu Kindkomponenten funktioniert, ist es an der Zeit, die Daten in die andere Richtung fließen zu lassen. Mit der Kommunikation von der Kind- zur Elternkomponente können Sie Ihre Aufgaben wieder als erledigt markieren. Der Datenfluss geht in diesem Fall wie bei Angular und React über Events, die in der Kindkomponente ausgelöst werden und auf die sich die Elternkomponente mit Event Listenern subscriben kann. Durch das Beispiel mit dem Klick-Listener wissen Sie bereits, dass Sie sich mit der v-on-Direktive auf Events subscriben können. Diesen Mechanismus machen Sie sich auch bei der Kommunikation mit Ihren Kindkomponenten zunutze. Was Sie für die Implementierung außerdem noch wissen müssen, ist, dass jede Komponente ein Event Emitter ist. Das bedeutet, dass Sie mit der $emit-Methode benutzerdefinierte Events auslösen können. Um eine Aufgabe als erledigt beziehungsweise nicht erledigt markieren zu können, müssen Sie nichts weiter tun als in der Kindkomponente die toggleState-Methode in der methods-Eigenschaft zu implementieren und in dieser mithilfe der $emit-Methode das toggle-state-Event auszulösen. Event-Namen werden von Vue.js nicht umgeschrieben. HTML ist nicht case-sensitive. Das bedeutet, dass es bei Event-Namen wie toggleState zu Problemen kommen kann. Die Empfehlung lautet daher, für Events Namen in kebab-case zu verwenden. Für das Beispiel bedeutet das toggle-state statt toggleState. In Listing 10 finden Sie die Anpassungen der Kindkomponente.

<script>
  export default {
    props: ['todo'],
    methods: {
      toggleState() {
        this.$emit('toggle-state', this.todo.id);
      }
    }
  }
</script>

In der Elternkomponente müssen Sie jetzt nur noch die bestehende toggleState-Methode mit dem Event der Kindkomponente über das v-on:toggle-state-Attribut verbinden. Die Kindkomponente übermittelt mit dem Event die ID des betroffenen Datensatzes. Auf diese können Sie, wie in Listing 11 zu sehen, über die Variable $event zugreifen.

<template>
  <ul>
    <TodoListItem v-for="todo in todos" v-bind:todo="todo" v-bind:key="todo.id" 
     v-on:toggle-state="toggleState($event)"></TodoListItem>
  </ul>
</template>

Serverkommunikation und Lifecycle Hooks

Bis jetzt verlieren Sie sämtliche Informationen, die Sie in Ihrer Applikation erzeugt haben, bei einem Reload wieder, da der Zustand der Applikation lediglich im Speicher liegt. In der Regel werden solche Applikationsdaten jedoch auf einem zentralen Webserver vorgehalten. Und so soll es auch in dieser einfachen To-do-Liste sein. Im Produktivbetrieb befinden sich der Quellcode des Clients und die Serverschnittstelle meist auf demselben System oder zumindest hinter einer einheitlichen Schnittstelle, sodass es keine Probleme bei Ajax Calls gibt. Während der Entwicklung ist die Situation eine andere: Ihre Vue.js-Applikation wird über den DevServer des CLI ausgeliefert. Das Backend, das Ihnen die Daten liefert, läuft auf einem separaten Webserver. Um hier ein möglichst realistisches Szenario zu simulieren und Hacks zu vermeiden, können Sie eine Datei mit dem Namen vue.config.js im Root-Verzeichnis Ihrer Applikation anlegen. Mithilfe dieser Datei können Sie den DevServer so konfigurieren, dass er Ajax Calls zu Ihrem Entwicklungs-Backend weiterleitet. Listing 12 enthält den erforderlichen Quellcode.

module.exports = {
  devServer: {
    proxy: 'http://localhost:8080',
  },
};

Für die To-do-Liste nehmen wir an, dass Sie über einen Server verfügen, der Ihnen die Daten über den URL http://localhost:8080/todo liefert. Im einfachsten Fall installieren Sie hierfür auf Ihrem System das npm-Paket json-server und erzeugen eine entsprechende Quelldatei. Nachdem Sie den Server gestartet, die Proxy-Konfiguration für Ihre Vue.js-Applikation erzeugt und die Applikation neu gestartet haben, können Sie die Daten vom Server holen. Vue.js verfügt selbst über keinerlei Möglichkeit, Daten vom Server zu holen. Allerdings bieten alle modernen Browser mit dem fetch-API eine komfortable Lösung hierfür. Für Aktionen wie das Abholen von Daten von einem Server sieht Vue.js verschiedene Hooks im Lebenszyklus einer Komponente vor. Der Lebenszyklus besteht insgesamt aus den vier Phasen Create, Mount, Update und Destroy. Create steht dabei für die Erzeugung der Komponente, Mount bezeichnet die Phase, in der eine Komponente gerendert wird, Update tritt bei Datenänderungen ein und Destroy markiert das Ende des Komponentenlebens.

Für jede dieser Phasen gibt es einen Hook, der vor und einen, der nach dem Abschnitt greift. Der Hook, der normalerweise für das Abholen von Daten verwendet wird, ist der mounted-Hook. Um eine solche Hook-Funktion zu schreiben, erzeugen Sie in der Komponente eine Methode mit dem entsprechenden Namen, in diesem Fall mounted, und platzieren dort die gewünschte Funktionalität. Das fetch-API arbeitet Promise-basiert. Um hier unnötige Callback-Funktionen zu vermeiden, können Sie den mounted-Hook als async-Methode schreiben, sodass Sie das await-Schlüsselwort nutzen können. Das Abrufen der Daten geschieht in einem zweistufigen Prozess: Zuerst formulieren Sie mit der fetch-Funktion Ihre Anfrage. Auf dem Rückgabewert dieser Funktion rufen Sie anschließend die json-Methode auf, um an die Daten zu gelangen. Diese Daten, das Array an Aufgaben, können Sie anschließend der todos-Eigenschaft der Komponente zuweisen. Den Rest der Arbeit übernimmt Vue. js für Sie, erzeugt die Kindkomponente und stellt sie dar. Listing 13 enthält den Quellcode.

<script>
  import TodoListItem from './TodoListItem';

  export default {
    async mounted() {
      const response = await fetch('/todo');
      this.todos = await response.json();
    },
…
</script>

Die Auswirkungen der Zustandsänderung einer Aufgabe sind aktuell auch noch auf das lokale System beschränkt. Hier können Sie Abhilfe schaffen, indem Sie in der TodoList-Komponente eine schreibende Anfrage an den Server senden. Listing 14 enthält den angepassten Quellcode der toggleState-Methode.

async toggleState(id) {
  const index = this.todos.findIndex((todo) => todo.id === id);
  const todo = this.todos[index];
  todo.done = !todo.done;
  await fetch(`/todo/${todo.id}`, {
    method: 'PUT', 
    headers: {'content-type': 'application/json'},
    body: JSON.stringify(todo),
  });
},

Formularhandling

Im letzten Schritt implementieren Sie nun noch die Möglichkeit, neue Aufgaben in Ihrer To-do-Liste anzulegen. Zu diesem Zweck legen Sie zunächst eine neue Komponente TodoForm an. Diese Komponente ist dafür zuständig, dem Benutzer ein Formular zur Erstellung neuer Datensätze anzuzeigen. Für das Anlegen reicht ein Eingabefeld für den Titel und eine Checkbox für den Status aus. Schließlich benötigen Sie noch einen Button, um das Formular abzusenden. Vue.js stellt Ihnen mit der v-model-Direktive eine Möglichkeit zur Verfügung, mit der Sie ein JavaScript-Objekt in der Komponente und ein Formularelement synchronisieren können. Dieser als Two-Way Data Binding bekannte Mechanismus kommt in ähnlicher Form auch beispielsweise bei Angular in Form des ngModels zum Einsatz. Ändert sich der Wert des Objekts, wird die Anzeige im Template angepasst und umgekehrt. Das bedeutet auch, dass sich Benutzereingaben direkt auf die JavaScript-Objektstruktur auswirken. Bis jetzt lag es in der Verantwortung der TodoList-Komponente, die Serverkommunikation zu übernehmen, und dabei soll es auch bleiben. Hängen Sie die TodoForm-Komponente als Kindkomponente in die TodoList, können Sie diese über ein Event von einem neuen Datensatz benachrichtigen. Binden Sie nun einen Event Handler an das Click-Event des Buttons in der TodoForm-Komponente, können Sie ein Event mit dem neu erstellten Datensatz triggern, und die TodoList sendet die Daten an den Server. Listing 15 zeigt Ihnen die Integration sowie die Callback-Funktion zum Speichern.

<template>
  <form>
    <div>
      <label for="title">Title: </label>
      <input type="text" v-model="todo.title" name="title" id="title">
    </div>
    <div>
      <label for="done">Done: </label>
      <input type="checkbox" v-model="todo.done" name="done" id="done">
    </div>
    <button v-on:click="save">save</button>
  </form>
</template>

<script>
  export default {
    data() {
      return {
        todo: {
          title: '',
          done: false
        }
      }
    },
    methods: {
      save() {
        this.$emit('save', this.todo);
      }
    }
  }

</script>

<style scoped></style>
Listing 14: TodoForm-Komponente

<template>
  <TodoForm v-if="create" v-on:save="save($event)"></TodoForm>
  <ul v-else>
    <TodoListItem v-for="todo in todos" v-bind:todo="todo" v-bind:key="todo.id" 
     v-on:toggle-state="toggleState($event)"></TodoListItem>
    <button v-on:click="create = true">new</button>
  </ul>
</template>

<script>
  import TodoListItem from './TodoListItem';
  import TodoForm from './TodoForm';

  export default {
    async mounted() {…},
    components: {
      TodoListItem,
      TodoForm
    },
    name: 'TodoList',
    data() {
      return {todos: [], create: false};
    },
    methods: {
      async toggleState(id) {…},
      async save(todo) {
        await fetch('/todo', {
          method: 'POST', 
          headers: {'content-type': 'application/json'},
          body: JSON.stringify(todo), 
        });
        this.create = false;
      }
    }
  }
</script>

<style scoped>
…
</style>

Vue, Angular oder React? Ein Fazit

Trotz seines leichtgewichtigen Ansatzes und seiner geringen Einstiegshürde sollten Sie Vue.js nicht unterschätzen. Gerade im Vergleich mit Angular und React kann sich der Newcomer unter den JavaScript-Frameworks sehen lassen. Sollten Sie schon Erfahrung in einem der beiden anderen Frameworks haben, sollte Ihnen der Einstieg in Vue.js recht leicht fallen, da sich die Frameworks in zahlreichen Ansätzen ähneln, wie beispielsweise die Komponentenorientierung oder die Art der Kommunikation im Komponentenbaum. Aber es gibt auch bedeutende Unterschiede. So bringt Angular bereits für zahlreiche Aspekte der Applikationsentwicklung eine Lösung mit, mit dem Nachteil, dass das Ihre Freiheit als Entwickler einschränkt.

React und Vue. js verfolgen hier ähnliche Ansätze. Beide Frameworks lassen Ihnen als Entwickler sehr viele Freiheiten, was allerdings den Nachteil hat, dass Sie zusätzliche Pakete in Ihre Applikation integrieren müssen. Im Fall von Vue sind dies Hilfsmittel wie das Vue CLI, VueX zur Verwaltung des Applikationszustands oder der Vue.js-Router. Insgesamt hat sich um Vue.js bereits eine sehr rege Community gebildet, die zahlreiche Erweiterungen für das Framework zur Verfügung stellt.

Unsere Redaktion empfiehlt:

Relevante Beiträge

X
- Gib Deinen Standort ein -
- or -