­čôő Kapitel 2: Baue eine Haustier-Galerie

Ziel Lerne wie du Daten in der Webanwendung ver├Ąndern kannst
Was du lernen wirst Verwendung von statischen Daten. Du baust eine Oberfl├Ąche aus Kacheln, die Adoptivhunde anzeigt
Was du daf├╝r ben├Âtigst Einen modernen Browser, z.B. Google Chrome. Einen Account bei CodeSandbox.io. Falls du nicht mehr wei├čt, wo du warst, kannst du die Basis f├╝r dieses Kapitel von hier importieren. Wie das geht, steht im Anhang 1
Dauer 1 Stunde

Anleitung

Falls du das Projekt von vorn beginnen musst, klone dieses Projekt in Code Sandbox, nachdem du dich eingeloggt hast. Daf├╝r klickst du auf den Link Import form Github unten links auf der Hauptseite und f├╝gst die URL des Repositories in das Feld. Du kannst ebenfalls mit dem Projekt fortfahren, dass du in Kapitel 1 erstellt hast.

Aktuell hat unser Pet Shop nur eine Homepage. Wir m├Âchten eine weitere Seite hinzuf├╝gen, auf der in mehreren Kacheln Haustiere angezeigt werden k├Ânnen. Wir erstellen eine Single-Page Anwendung mit einer Navigation und zwei Navigationspunkten: "home" und "pets" (=Haustiere). Wenn man auf "pets" klickt, wird die neue Seite angezeigt, die wir jetzt erstellen und "home" wird eine Seite ├Âffnen, die wir in Kapitel 1 erstellt haben.

­čĺí

"A single-page application (SPA) is a web application or web site that interacts with the user by dynamically rewriting the current page rather than loading entire new pages from a server" (Wikipedia)

Um eine SPA mit Vue zu bauen, ben├Âtigen wir den vue-router. Der vue-router ist der offizielle Router f├╝r Vue.js, die Bibliothek mit der man einfach und effizient zwischen meheren Seiten navigieren kann. Der vue-router ist genau f├╝r die Verwendung mit SPAs gebaut. SPAs haben einige spezifische Anforderungen, wie z.B. verschachtelte Routen oder Daten├╝bertragung. F├╝ge den vue-router zu den Abh├Ąngigkeiten deiner Vue-App hinzu (Klicke auf Add Dependency und suche nach vue-router). Du wirst sehen, dass es in dem depencendies Objekt in unserer package.json hinzugef├╝gt wurde.

Der Router

├ľffne die Datei main.js und importiere vue-router:

import VueRouter from 'vue-router';
1

Du solltest nun diese vier Import-Zeilen hinzuf├╝gen:

import Vue from "vue";
import App from "./App.vue";
import vuetify from "@/plugins/vuetify";
import VueRouter from "vue-router";
1
2
3
4

Jetzt m├╝ssen wir das Plugin bei der Vue-App registrieren mit Hilfe der globalen Vue.use()-Methode:

Vue.use(VueRouter);
1

F├╝ge diese Zeile vor new Vue(...) hinzu, um sicherzustellen, dass jede neue Instanz von Vue, die wie erstellen, den vue-router benutzen wird. Wenn du die Zeile hinter new Vue(...) hinzuf├╝gen w├╝rdest, w├╝rde der vue-router in unserer Applikation nicht zur Verf├╝gung stehen.

­čĺí

├ťberlege f├╝r einen Moment, wie die App aufgebaut sein muss. Der Header und Footer sollen auf jeder Seite gleich sein. Der eigentliche Inhalt dazwischen soll sich ver├Ąndern, je nach dem auf welchem Navigationspunkt man klickt. Die Komponente, die zu der Route (=dem geklickten Navigationspunkt) passt, wird in einem <router-view>-Tag angezeigt. Das hei├čt wir m├╝ssen unseren Code ver├Ąndern, damit nicht mehr alles in der App.vue steht. Weil der Header und Footer jederzeit sichtbar sein sollen, bleiben sie in der App.vue. Der Inhalt der spezifischen Seiten wird in separate Komponten veschoben. Wir werden somit davon wegkommen, dass alle Teile unserer Applikation in die App.vue sind, wir werden also ein Refactoring durchf├╝hren.

Eine Homepage erstellen

Wir erstellen eine separate Komponente f├╝r alle Elemente in <div class="wrapper">.

  • Gehe in den views-Ordner in src, falls dieser nicht existiert, erstelle ihn zuerst. In diesem Ordner erstelle eine Datei namens Home.vue.

  • F├╝ge den <template></template>-Tag in diese Datei ein.

  • ├ľffne die App.vue-Datei. Kopiere das <div class="wrapper"> und alle Elemente darin in dem template-Tag in Home.vue. Du solltest dort nun allen Code, der zwischen <header> und <footer> stand, stehen haben. L├Âsche diesen Teil aus App.vue.

Du wirst sehen, dass unsere Applikation etwas leer aussieht, aber keine Sorge - wir werden die entfernten Bestandteile sp├Ąter wieder hinzuf├╝gen.

Eine Haustier-Seite erstellen

Jetzt erstellen wir eine Seite f├╝r die Haustiere. Erstelle im src/views-Ordner eine neue Datei Pets.vue, genauso wie du es mit Home.vue gemacht hast. Kopiere folgenden Code f├╝r das Layout der Seite.

<template>
  <v-container grid-list-md fluid>
    <v-layout wrap>
      <v-flex xs12 sm4 md3>
        <v-card color="grey lighten-2">
          <v-img src="https://goo.gl/6CQNDo" height="170px">
          </v-img>
          <v-card-title>
            <div>
              <h3>Looking for a dog?</h3>
            </div>
          </v-card-title>
        </v-card>
      </v-flex>
    </v-layout>
  </v-container>
</template>

<style scoped>
p {
  margin: 0;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Die Routen hinzuf├╝gen

Super! Jetzt haben wir zwei verschiedene Komponenten f├╝r unsere Startseite und die Haustier-Galerie. Wie du sicher schon bemerkt hast, wird das aber noch nicht in der App angezeigt. Daf├╝r m├╝ssen wir zwei Routen erstellen.

  • Zur├╝ck zur main.js. Zurerst importieren wir die neuen Kopmonenten nach den anderen Importen:
import Home from './views/Home';
import Pets from './views/Pets';
1
2
  • Jetzt erstellen wir die Routen. Jede Route ist ein Objekt, das einen Pfad und eine Komponente enth├Ąlt. F├╝ge die zwei Routen unter Vue.use... ein (eine ist f├╝r die Startseite, die andere f├╝r die Haustier-Galerie):
const routes = [
  {
      path: '/',
      component: Home
  },
  {
      path: '/pets',
      component: Pets
  },
];
1
2
3
4
5
6
7
8
9
10
  • Jetzt m├╝ssen wir eine VueRouter-Instanz erstellen und dieser unsere Routen ├╝bergeben. Kopiere diese Zeile unter const routes:
const router = new VueRouter({ routes });
1
  • Zum Schluss m├╝ssen wir den Router noch der Vue-App hinzuf├╝gen:
new Vue({
  vuetify,
  router,
  render: h => h(App)
}).$mount("#app");
1
2
3
4
5
  • ├ľffne jetzt die App.vue-Datei. Schreibe an die Stelle, an der vorher <div class="wrapper"> stand, den <router-view></router-view>-Tag. Er sollte zwischen dem Header und Footer stehen. Und nun wird in der App auch wieder etwas angezeigt!

Teste deinen Code. F├╝ge /pets an das Ende der URL, jetzt kannst du die Haustier-Galerie sehen anstelle der Startseite.

Um das Wechseln zwischen den beiden Seiten einfacher zu machen, bauen wir eine Navigation ein. Daf├╝r werden wir Vuetify nutzen, das wir bereits in Kapitel 1 hinzugef├╝gt haben.

Die Toolbar-Komponente von Vuetify hei├čt v-toolbar. Kopiere sie in der App.vue direkt unter den h1-Tag in den Header:

<v-toolbar>
    <v-toolbar-items>
        <v-btn to="/" flat>Home</v-btn>
        <v-btn to="/pets" flat>Pets</v-btn>
    </v-toolbar-items>
</v-toolbar>
1
2
3
4
5
6

Du siehst jetzt zwei Buttons in dieser Toolbar. Jeder hat ein to-Attribut: Das ist ein router-link, der auf eine bestimmte Route zeigt. Jetzt k├Ânnen wir ganz einfach zwischen den Seiten wechseln, probiere es aus!

Ok, sch├Ân. Aber da sind noch keine Haustiere. Die bauen wir jetzt ein!

Daten erstellen

Wir werden zun├Ąchst ein paar Dummy-Daten hinzuf├╝gen. Erstelle dazu im src-Ordner einen neuen Ordner namens data und in diesem eine neue Datei namens dogs.js. Kopiere folgendes JSON-Objekt in die Datei:

export const Dogs = [
  {
    name: 'Max',
    breed: 'husky',
    img: 'https://images.dog.ceo/breeds/husky/n02110185_1469.jpg',
  },
  {
    name: 'Rusty',
    breed: 'shiba',
    img: 'https://images.dog.ceo/breeds/shiba/shiba-13.jpg',
  },
  {
    name: 'Rocco',
    breed: 'boxer',
    img: 'https://images.dog.ceo/breeds/boxer/n02108089_14112.jpg',
  },
  {
    name: 'Zoey',
    breed: 'beagle',
    img: 'https://images.dog.ceo/breeds/beagle/n02088364_11136.jpg',
  },
  {
    name: 'Duke',
    breed: 'doberman',
    img: 'https://images.dog.ceo/breeds/doberman/n02107142_4653.jpg',
  },
  {
    name: 'Lily',
    breed: 'malamute',
    img: 'https://images.dog.ceo/breeds/malamute/n02110063_1104.jpg',
  },
  {
    name: 'Winston',
    breed: 'pug',
    img: 'https://images.dog.ceo/breeds/pug/n02110958_15626.jpg',
  },
  {
    name: 'Angel',
    breed: 'samoyed',
    img: 'https://images.dog.ceo/breeds/samoyed/n02111889_4470.jpg',
  },
];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

Hier wird eine Konstante (const) names Dogs exportiert, die alle Daten beinhaltet, die wir ben├Âtigen.

  • Jetzt importieren wir diese Daten in die pets-Komponente. ├ľffne die Pets.vue-Datei und kopiere den folgenden <script> Block unter den <template>-Block.
<script>
import { Dogs } from "../data/dogs";
</script>
1
2
3

Dieser Teil importiert die Daten der Hunde. Jetzt m├╝ssen wir diese Daten der data()-Funktion hinzuf├╝gen. Bearbeite den <script> Block:

<script>
  import { Dogs } from "../data/dogs";
  export default {
    data() {
      return {
        dogs: Dogs
      };
    }
   };
  </script>
1
2
3
4
5
6
7
8
9
10

Dieses Skript stellt sicher, dass das dogs-Array ein Teil des Zustands ('state') der Pets-Komponente ist und im Template verwendet werden kann. Als n├Ąchstes werden wir unser Template erweitern, so dass es die Daten des dogs-Arrays anzeigt.

Die Daten in einer Liste ausgeben

Jetzt m├Âchten wir eine Liste von Hunden erzeugen. Der einfachste Weg, um das zu erreichen, ist, ├╝ber das Array zu iterieren und die Daten an eine Liste anzuh├Ąngen. Unsere dogs sind ein Array (=Liste von Objekten) und damit bereit verarbeitet zu werden. Um eine Liste von Eintr├Ągen darzustellen, die in einem Array stehen, gibt es in Vue die v-for Direktive.

Diese Direktive f├╝gen wir dem v-flex-Element in Pets.vue hinzu:

<v-flex xs12 sm4 md3 v-for="pet in dogs" :key="pet.breed">...</v-flex>
1

Um korrekt ├╝ber das Array zu iterieren und die Daten auszugeben, muss jedes Element ein eindeutiges Schl├╝sselattribut (=key attribute) haben. In unserem Fall wird die Art des Hundes dieses Schl├╝sselattribut sein.

Jetzt haben wir acht v-cards mit dem gleichen Text und Bild. Das stimmt so noch nicht.

In der v-for-Direktive wird der aktuelle Hund pet genannt.

­čĺí

Wir haben diesen Namen in der Diretive zugewiesen; h├Ątten wir geschrieben v-for="dog in dogs" w├╝rde das aktuelle Element dog hei├čen.

In der dog.js kannst du sehen, dass jeder Hund drei Eigenschaften hat: Name (name), Art (breed) und Bild (img). Das Bild k├Ânnen wir mit der v-img-Komponente anzeigen.

Wenn wir src nur mit dem Attriubut pet.img ersetzen...

<v-img src="pet.img" height="170px">
1

... werden noch keine Bilder angezeigt. Warum? Weil wir so einen statischen Wert einsetzen, die App erwartet eine Datei mit dem Namen pet.img. Diese Datei gibt es allerdings nicht. Um den Wert von pet.img dynamisch in das src-Attribut zu setzen, m├╝ssen wir die v-bind-Direktive (oder den Shortcut :) nutzen.

<v-img :src="pet.img" height="170px"></v-img>
1

­čĺí

Die v-bind-Direktive erzeugt dynamisch aus ein oder mehreren Attributen, oder sogar eine Komponenten-Variable einen JavaScript-Befehl. Den Unterschied macht der :!

Es funktioniert!

Jetzt zeigen wir den Namen des Hundes an. F├╝r Text wird in Vue die "mustache"-Syntax (=Schnauz) genutzt - doppelte geschweifte Klammern: {{ }}. Dieser Tag wird durch den Wert der zugewiesenen Eigenschaft ersetzt. Bearbeite den <h3>-Tag mit dem Namen des Hundes, nutze daf├╝r die geschweiften Klammern:

<h3>{{pet.name}}</h3>
1

Jetzt fehlt noch die Art des Hundes. F├╝ge einen weiteren <p></p> Tag direkt unter dem Namen ein und zeige die Art des Hundes an:

<p>{{pet.breed}}</p>
1

Soweit funktioniert alles, wie wir es uns vorgestellt haben. Nur das Template ist inzwischen etwas un├╝bersichtlich geworden. Wir k├Ânnen es ├╝berarbeiten und etwas verschlanken. Daf├╝r erstellen wir eine Dog-Komponente und ├╝bergeben das aktuelle Haustier als Eigenschaft (=property).

­čĺí

Eigenschaften (=properties) sind spezielle Attribute, die man einer Komponente zuweisen kann. Wenn ein Wert an ein Eigenschaftsattribut zugewiesen wird, wird dieser Wert eine Eigenschaft f├╝r diese eine Ausf├╝hrung der Komponente. In unserem Fall wird die Dog-Komponente eine dog Property haben, die sie von der Eltern-Komponente Pets ├╝bergeben bekommt.

├ťberarbeitung des Templates - Property!

Erstelle einen neuen Ordner components im src-Ordner.

Erstelle eine neue Datei Dog.vue in dem components-Ordner und schreibe die <template></template> und <script></script>-Tags hinein. So sieht die neue Datei jetzt aus:

<template>

</template>

<script>

</script>
1
2
3
4
5
6
7

Kopiere die gesamte v-card-Komponente aus Pets.vue in den <template>-Tag der Dogs-Komponente. Den Teil kannst du nun aus dem template in Pets.vue l├Âschen.

Wie bereits erw├Ąhnt, ben├Âtigen wir eine dog-Property in der Dog-Komponente. F├╝ge dazu die props zu der Komponente hinzu: Zuerst muss in den <script>-Tag eine Export-Anweisung; das erm├Âglicht uns sp├Ąter die Dogs-Komponente in der Pets-Komponente zu importieren und nutzen. Kopiere diesen <script>-Block nach Dogs.vue:

<script>export default {}</script>
1

Jetzt k├Ânnen wir die props und die Eigenschaft dog hinzuf├╝gen:

<script>
	export default {
	  props: {
	    dog: {
	      type: Object
	    }
	  }
	};
</script>
1
2
3
4
5
6
7
8
9

An dieser Stelle definieren wir auch den Typ der Eigenschaft - es soll ein JavaScript-Objekt sein.

In dem Template von Dog.vue musst du pet mit dog ersetzen, weil es innerhalb der Dog-Komponente keine pet-Variable gibt. So sollte das Template jetzt aussehen:

<template>
	<v-card color="grey lighten-2">
	  <v-img :src="dog.img" height="170px">
	  </v-img>
	    <v-card-title>
	      <div>
	        <h3>{{dog.name}}</h3>
	        <p class="breed">{{dog.breed}}</p>
	      </div>
	    </v-card-title>
	</v-card>
</template>
1
2
3
4
5
6
7
8
9
10
11
12

In der Pets.vue-Datei müssen wir noch ein paar Änderungen machen. Zuerst importieren wir die neue Dog-Komponente; kopiere dazu diese Zeile unter den Import der Dogs-Komponente:

import Dog from '../components/Dog.vue';
1

Nun m├╝ssen wir der Pets-Komponente mitteilen, dass sie eine sogenannte Kind-Komponente beinhaltet. Vue nutzt die components-Option daf├╝r; diese wird ├╝ber data() deklariert:

export default {
  components: {
    appDog: Dog,
  },
  data() {
    return {
      dogs: Dogs,
    };
  },
};
1
2
3
4
5
6
7
8
9
10

­čĺí

Jede Zuweisung in der components-Option besteht aus einem Schl├╝ssel (=key) und einem Wert (=value). Der Key ist der Name des neuen Elementes und der Value beinhaltet options-Objekt f├╝r diese Komponente.

­čĺí

F├╝r den Namen der Komponente kannst du verschiedene Schreibweisen benutzen: camel-case (appDog) oder kebab-case ('app-dog'). Die Camel-case-Schreibweise wird im HTML-Tag in Kamel-Case "umgewandelt". Um die appDog-Komponente anzuzeigen, m├╝ssen wir den HTML-Tag <app-dog> nutzen und es wird das Template aus der Dog-Komponente angezeigt.

F├╝ge den neuen <app-dog>-Tag in Pets.vue an die Stelle ein, an der du zuvor die <v-card> gel├Âscht hast.

<v-flex xs12 sm4 md3 v-for="pet in dogs" :key="pet.breed">
   <app-dog></app-dog>
</v-flex>
1
2
3

Jetzt m├╝ssen wir der Dog-Komponente noch die dog-Eigenschaft ├╝bergeben. Daf├╝r nutzen wir wieder die v-bind-Direktive (oder den Shortcut :). Passe deinen gerade geschriebenen Code in Pets.vue entsprechend an:

<v-flex xs12 sm4 md3 v-for="pet in dogs" :key="pet.breed">
  <app-dog :dog="pet"></app-dog>
</v-flex>
1
2
3

Jetzt solltest du ein h├╝bsches Kachel-Layout mit vielen Hunden haben! Kapitel 2 ist damit abgeschlossen!

Ergebnis

final result chapter 2