Vue ist ein sogenanntes Javascript-Framework: Dieses wurde selbst in Javascript programmiert und läuft deshalb auf einer HTML-Seite im Browser. Mit Vue kann man interaktive WebApps programmieren.
Installation
Javascript laden
Wir können den von Vue verwendeten Javascript-Code direkt im HTML-Dokument verlinken. Der Browser lädt ihn so selbst vom Netz herunter. Dazu bauen wir im Head unserer HTML-Datei folgendes script-Element ein:
html
<script src="https://unpkg.com/vue@3"></script>
Vue-App initialisieren
Anschliessend muss die App initialisiert werden. Dazu ruft man Vue.createApp()
(mit entsprechenden Argumenten) auf und verbindet die App mit einem HTML-Element über die mount
-Methode:
javascript
Vue.createApp().mount('#app')
html
<div id="app"></div>
Variablen
Vue definiert in der data()
-Funktion reaktive Variablen und Objekte. Diese können im HTML-Teil mit Hilfe einer Template-Sprache mit geschweiften Klammern dargestellt werden oder mit v-model
an Eingabe-Elemente gebunden werden.
html
<div id="app">
Dein Name: <input type="text" v-model="name" label="Name" />
Hello {{ name }}
</div>
javascript
Vue.createApp({
data() {
return {
name: 'Vue',
}
}
}).mount('#app')
Hello World
Diese Hello-World-Vue-App fasst das oben beschriebene zusammen:
html
<!DOCTYPE html>
<html lang="de">
<head>
<title>Hello Vue</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="name" />
Hello {{ name }}
</div>
<script>
Vue.createApp({
data() {
return {
name: 'Vue',
}
}
}).mount('#app')
</script>
</body>
</html>
Dein Name:
Hello Vue
Aufgabe
Teste das obenstehende Beispiel aus. Versuche weitere Variablen einzubauen.
Templates
Vue-Templates beinhalten HTML-Code mit speziellen Platzhaltern und Anweisungen für Vue. Es können so Werte angezeigt werden, Elemente bedingt angezeigt werden und auf Events reagiert werden:
Variablen ausgeben
Werte von Variablen können in doppelt geschweiften Klammern ausgegeben werden.
html
<p>Suche nach {{ search }}</p>
In der Klammer drin sind auch einfache Javascript-Ausdrücke möglich, z.B. mit dem «bedingten Operator» – sozusagen ein abgekürztes if-else – um etwas anzuzeigen sollte die Variable search
leer sein:
html
<p>Suche nach {{ search ? search : "–" }}</p>
Wir können das lesen wie folgt: «ist search
gesetzt? Dann den Wert von search
ausgeben, sonst einen Bindestrich ausgeben»
Variablen ändern
Man kann Vue-Variablen mittels v-model
an HTML-Input-Elemente knüpfen:
html
<input type="text" v-model="search" />
Das Text-Feld zeigt den Wert von search
an – aber man kann ihn damit auch ändern.
Beispiel Variablen
Suche:
Suche nach –
Listen
Listen von Elementen brauchen eine Wiederholung zur Darstellung. In Vue verwendet man dafür die v-for
-Direktive. Das für die Direktive verwendete HTML-Element wird für jeden Eintrag in der Liste dargestellt. Im Element drin kann man auf das Element der Liste zugreifen:
html
<div v-for="movie in movies">
<h1>{{ movie.title }}</h1>
<p>{{ movie.year }}</p>
</div>
- Zeile 1
- das
div
-Element wir für jedenmovie
aus der Listemovies
wiederholt - Zeile 2 & 3
movie
ist ein Objekt aus der Listemovies
- mit der Punktnotation können wir auf die einzelnen Eigenschaften zugreifen
- Zeile 4
- Das
div
-Element – und somit auch der Zugriff aufmovie
– wird beendet
if-elseif-else
Ein HTML-Element kann mit der v-if
-Direktive bedingt gerendert werden. Der Ausdruck wird ausgewertet und das HTML-Element nur dargestellt, wenn die Auswertung true
ergibt. Das direkt nachkommende HTML-Element kann mit einer v-else
-Direktive versehen werden.
html
<div v-for="movie in movies">
<h1>{{ movie.title }}</h1>
<p v-if="movie.year > 2021">Neu!!</p>
<p v-else>{{ movie.year }}</p>
</div>
Seit Vue 3.2 sind zwischen v-if
und v-else
ein oder mehrere Elemente mit v-elseif
möglich.
Ereignisse
Ereignisse verwenden wir meistens wenn die Maus etwas anklickt. Dazu können wir die @click
-Direktive verwenden:
html
<div v-for="movie in movies" @click="showDetails(movie.id)">
<h1>{{ movie.title }}</h1>
<p>{{ movie.year }}</p>
</div>
- Zeile 1
- bei jedem Film binden wir das Klick-Event auf die Methode
showDetails
und übergeben dieser die ID des Film. Diese sollte dann Details zum Film anzeigen.
Methoden
Die Vue-App kann Methoden definieren die wir dann entweder als Ereignis oder automatisch aufrufen können:
javascript
Vue.createApp({
data() {
return {
name: 'Vue',
movies: []
}
},
methods: {
async getMovies() {
const response = await fetch("https://informatik.mygymer.ch/fts/rest/movies/");
const json = await response.json();
this.movies = json.movies;
},
showDetails(id) {
// fetch movie-Details and show in App
}
}
}).mount('#app')
Hooks
Mit den sogenannten Hooks kann man sozusagen im Vue-Programm-Ablauf «ein-haken». So wird z.B. der created
-Hook aufgerufen, sobald die Vue-App erzeugt wurde. Er lässt sich praktisch verwenden um erste Daten zu laden:
javascript
Vue.createApp({
data() {
return {
name: 'Vue',
movies: []
}
},
methods: {
async getMovies() {
const response = await fetch("https://informatik.mygymer.ch/fts/rest/movies/");
const json = await response.json();
this.movies = json.movies;
},
showDetails(id) {
// fetch movie-Details and show in App
}
},
created() {
this.getMovies()
}
}).mount('#app')
Komplettes Beispiel
html
<!DOCTYPE html>
<html>
<head>
<title>Movies</title>
<script src="https://unpkg.com/vue@3"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="app">
<header><h1>@theMovies</h1></header>
<article v-if="movie">
<ul>
<li v-on:click="movie = false" class="clickable">
<p>zurück zur Liste</p>
</li>
<li>
<img :src="'https://informatik.mygymer.ch/fts/rest/media/movies/'+movie.id" />
</li>
<li>
<h1>{{movie.title}}</h1>
<p>erschienen: {{movie.year}}</p>
<p v-if="movie.actors && movie.actors.length > 0">{{movie.actors.length}} Schauspieler:innen erfasst</p>
<p v-else>keine Schauspieler:innen erfasst</p>
</li>
</ul>
<ul>
<li v-for="actor in movie.actors">
<img :src="'https://informatik.mygymer.ch/fts/rest/media/actors/'+actor.id" />
<p>{{actor.name}}<br>{{actor.as_character}}</p>
</li>
</ul>
</article>
<article v-else>
<ul>
<li v-for="movie in movies" v-on:click="getMovie(movie.id)" class="clickable">
<img :src="'https://informatik.mygymer.ch/fts/rest/media/movies/'+movie.id" />
<p>{{movie.title}}</p>
</li>
</ul>
</article>
<footer></footer>
</div>
<script>
Vue.createApp({
data() {
return {
movies: [],
movie: false
}
},
methods: {
async getMovies() {
this.movies = [];
const response = await fetch("https://informatik.mygymer.ch/fts/rest/movies/");
const json = await response.json();
this.movies = json.movies;
},
async getMovie(id) {
this.movie = false;
const response = await fetch("https://informatik.mygymer.ch/fts/rest/movies/"+id);
const json = await response.json();
this.movie = json;
}
},
created() {
this.getMovies()
}
}).mount('#app')
</script>
</body>
</html>
css
/* https://www.colourlovers.com/palette/482774/dream_magnet*/
body {
background-color: #343838;
font-family: system-ui;
color: #00b4cc;
margin: 0;
padding: 0;
}
header {
background-color: #008c9e;
color: #343838;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
li {
min-width: 30%;
width: 200px;
margin: 10px;
list-style: none;
}
img {
width: 100%;
border: 1px solid #00b4cc;
}
li.clickable {
cursor: pointer;
}
li.clickable:hover {
color: #00dffc;
}
li.clickable img:hover {
border: 1px solid #00dffc;
}
article {
margin: 10px;
}
- Mit dem
created
-Hook wird die MethodegetMovies()
aufgerufen. - Diese lädt mit
fetch
eine Liste von Filmen - diese Filme werden im Template angezeigt
- klickt man auf einen Film, so wird die Methode
getMovie
ausgeführt - diese holt über die
id
Details (Liste der Schauspieler:innen) zu diesem Film und speichert diese in der Variablenmovie
- die Ansicht ändert nun
Das Ganze sieht wie folgt aus:
@theMovies
mehrere Seiten
Ev. lohnt es sich, die WebApp auf mehrere Dokumente aufzuteilen. Z.B. eine Suchseite search.html und eine Detail-Seite movie.html für den Film.
Damit die Detail-Seite aber weiss, um welchen Film es sich handelt, müssen wir beim Aufruf die Film-ID mitliefern. Dies können wir an die URL anhängen.
Querystring
Der Querystring wird durch ein Fragezeichen an die URL angehängt. Er beschreibt sogenannte Key/Value-Paare. Möchten wir z.B. die Datei movie.html
aufrufen und als id
den Wert 84
mitgeben würde die URL wie folgt aussehen:
movie.html?id=84
Wir können auch mehrere Key/Value-Paare mitliefern. Diese werden dann durch &
getrennt:
movie.html?id=84&language=en
Querystring-Parameter auslesen
Rufen wir eine Seite mit einem Querystring auf, dann können wir die Parameter mit Javascript auslesen.
Wenn wir also z.B. suche.html?q=Titanic
aufrufen, dann kann die Seite suche.html
mit Javascript auf den Querystring zugreifen. Dies geschieht in drei Schritten:
javascript
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const search = urlParams.get('q');
- Zeile 1
- wir holen den Querystring über die Eigenschaft
search
der URL des aktuellen Fensters - dies ergibt im Beispiel den String
q=Curry
- Zeile 2
- mit
URLSearchParams
können wir diesen String parsen, d.h. es wird überprüft, ob es sich um korrekte Parameter handelt und welche Datentypen dabei vorkommen. - Zeile 3
- mit der Methode
get()
vonURLSearchParams
können nun Werte für einzelne Elemente abgerufen werden. Wenn wir also den Wert für den Paramaterq
abfragen, erhalen wir nun den vom Beuntzer eingegebenen SuchbegriffTitanic
zurück.
Beispiel
Das selbe Beispiel wie oben aber auf zwei Seiten aufgeteilt:
html
<!DOCTYPE html>
<html>
<head>
<title>Movies</title>
<script src="https://unpkg.com/vue@3"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="app">
<header><h1>@theMovies</h1></header>
<article>
<ul>
<li v-for="movie in movies">
<a :href="'movie.html?id=' + movie.id">
<img :src="'https://informatik.mygymer.ch/fts/rest/media/movies/'+movie.id" />
</a>
<p>{{movie.title}}</p>
</li>
</ul>
</article>
<footer></footer>
</div>
<script>
Vue.createApp({
data() {
return {
movies: [],
}
},
methods: {
async getMovies() {
this.movies = [];
const response = await fetch("https://informatik.mygymer.ch/fts/rest/movies/");
const json = await response.json();
this.movies = json.movies;
},
},
created() {
this.getMovies()
}
}).mount('#app')
</script>
</body>
</html>
html
<!DOCTYPE html>
<html>
<head>
<title>Movies</title>
<script src="https://unpkg.com/vue@3"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div id="app">
<header><h1>@theMovies</h1></header>
<article>
<ul>
<li>
<a href="search.html">zurück zur Liste</a>
</li>
<li>
<img :src="'https://informatik.mygymer.ch/fts/rest/media/movies/'+movie.id" />
</li>
<li>
<h1>{{movie.title}}</h1>
<p>erschienen: {{movie.year}}</p>
<p v-if="movie.actors && movie.actors.length > 0">{{movie.actors.length}} Schauspieler:innen erfasst</p>
<p v-else>keine Schauspieler:innen erfasst</p>
</li>
</ul>
<ul>
<li v-for="actor in movie.actors">
<img :src="'https://informatik.mygymer.ch/fts/rest/media/actors/'+actor.id" />
<p>{{actor.name}}<br>{{actor.as_character}}</p>
</li>
</ul>
</article>
<footer></footer>
</div>
<script>
Vue.createApp({
data() {
return {
movie: false
}
},
methods: {
async getMovie(id) {
this.movie = false;
const response = await fetch("https://informatik.mygymer.ch/fts/rest/movies/"+id);
const json = await response.json();
this.movie = json;
}
},
created() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const id = urlParams.get('id');
this.getMovie(id)
}
}).mount('#app')
</script>
</body>
</html>
css
/* https://www.colourlovers.com/palette/482774/dream_magnet*/
body {
background-color: #343838;
font-family: system-ui;
color: #00b4cc;
margin: 0;
padding: 0;
}
header {
background-color: #008c9e;
color: #343838;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
li {
min-width: 30%;
width: 200px;
margin: 10px;
list-style: none;
}
img {
width: 100%;
border: 1px solid #00b4cc;
}
li.clickable {
cursor: pointer;
}
li.clickable:hover {
color: #00dffc;
}
li.clickable img:hover {
border: 1px solid #00dffc;
}
article {
margin: 10px;
}