Vue - Snippets: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
 
(79 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
== Vue Konzepte ==
+
== Links ==
=== Basics ===
+
[[Vue.js]]
* Deklarativer Ansatz
+
[[Vue - Basic Concepts]]
* Data Option / Function
+
[[Vue CLI]]
* Methods Option / Object
+
[[Vue - Components]]
* Outputting Data mit
 
** Interpolation {{}}
 
** Bindings v-bind:property="myVal"
 
** Methods
 
** JavaScript Objects
 
* this
 
 
 
  
 +
== Snippets ==
 +
=== Starters ===
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
// create App
 
const app = Vue.createApp();
 
// mount a html region
 
// app.mount('cssSelector');
 
app.mount('#myId'); // Vue controls now this id in the DOM
 
 
 
 
const app = Vue.createApp({
 
const app = Vue.createApp({
  // DATA FUNCTION can hold key val pairs
+
   data(){
   data() { //or data: function(){...}
+
     return{
     return{ // data always returns an object
 
      myVar: 'Learn Vue',// can store keys with vals of every type(bool, object, string...)
 
      myVar2: 'Master Vue<,
 
      myHTML: '<h3>HTML Code</h3>', // use v-html to output html code
 
      myLink: 'https://viewjs.org'
 
    };
 
  }
 
  // METHODS OBJECT HOLDS FUNCTIONS
 
  methods: {
 
    outputGoal(){
 
      const randomNumber = Math.random();
 
      if (randomNumber < 0.5) {return 'Learn Vue';}
 
      else {return this.myVar2} // 'this' works because vue merges all data and methods in a global vue object
 
 
     }
 
     }
 +
  },
 +
  methods:{
 +
  },
 +
  computed:{
 +
  },
 +
  watch:{
 
   }
 
   }
 
});
 
});
 +
app.mount('#assignment');
 
</syntaxhighlight>
 
</syntaxhighlight>
  
<syntaxhighlight lang="html5">
+
==== Starter mit main.js (CLI) ====
<div id="myId">
+
<syntaxhighlight lang="javascript">
<h3>Interpolation</h3>
+
import { createApp } from 'vue';
<p>{{ myVar }}</p> <!-- Interpolation outputs "Learn Vue" -->
+
// Import Main App
<h3>Binding</h3>
+
import App from './App.vue';
<p>Use bindings to set attributes. I.e. set the href attribute. {{myLink}} wouldn't work inside of tags.</p>
+
// Import Global Components
<p>Learn more <a v-bind:href="myLink">about Vue</a></p>
+
import BaseBadge from './components/BaseBadge.vue';
<p>{{ outputGoal() }}</p><!-- functions or simple js expresseions like 1+1 work to -->
+
import BaseCard from './components/BaseCard.vue'
<p v-html="myHTML"></p>
+
// Create App Instance
</div>
+
const app = createApp(App);
 +
// Register Components
 +
app.component('base-badge', BaseBadge);
 +
app.component('base-card', BaseCard)
 +
// Mount App
 +
app.mount('#app');
 +
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Im Beispiel sind einige der Basiskonzepte zu sehen.
+
=== Using this in a submethod i.e. Timer ===
 
 
==== data() Objekt ====
 
Die Funnktion data(){} ist eine Funktion die alle Properties initialisiert. Die Funnktion gibt ein Objekt mit allen Eigenschaften zurück: data(){ return {prop1: 'hallo'} }. Die Properties können Zahlen, Strings, Objekte... sein.
 
 
 
==== methods Objekt ====
 
Das Objekt methods{} gibt Methoden zurück die man nutzen kann. Es gibt noch computed und watch für ähnliche Aufgaben s.u.
 
 
 
==== Interpolations ====
 
Interpolations sind vereinfacht gesagt '''Platzhalter'''. Man kann man im HTML Template nutzen um Eigenschaften (oder den Rückgabewert von Funktionen oder auch Ausdrücke) auszugeben.
 
{{ myproperty }}
 
{{ myFunction }} // Referenz auf eine Funktion
 
{{ myFunction() }} // Funktion (wird direkt ausgeführt (vgl. methods, computed, watch)
 
{{ 1 + 1 }}
 
Da hier mehr als nur ein Einsetzen stattfindet greift Platzhalter eigentlich zu kurz. Vielmehr verkabelt (bindet) man Teile des Templates dynamisch an Ereignisse, Eigenschaften und Funktionen.
 
 
 
==== Deklarativer Ansatz ====
 
Dies bedeutet man '''deklariert wo etwas passieren''' soll und Vue prüft selbstständig ob sich etwas verändert hat und irgendwo etwas neu gerendert wird. Beim klassischen Ansatz würde man alles was neu gerendert wird selbst programmieren. In der Praxis setzt man die Interpolations und definiert im HTML Code Bindings und Event Handler und überläßt Vue dann die Überwachung was damit passieren soll.
 
 
 
==== v-bind ====
 
Mit v-bind kann man P'''roperties auch in HTML Attributen nutzen'''. Interpolations funktionieren nur zwischen HTML-Tags.
 
<a v-bind:href="myLink">about Vue</a>
 
 
 
===== Shortcut v-bind =====
 
v-bind: kann durch : ersetzt werden
 
  <a :href="myLink">about Vue</a>
 
 
 
==== v-html ====
 
Benötigt man wenn '''reiner HTML Code''' ausgegeben wird. Interpolations escapen HTML aus Sicherheitsgründen.
 
 
 
==== this ====
 
Mit this kann man auf das '''globale Datenobjekt''' zugreifen. Man kann damit z.B. in methods auf alle Eigenschaften in data zugreifen. Und diese auch setzten.
 
this.myVar = 'Hallo Welt'
 
 
 
=== Event Handling ===
 
==== v-on ====
 
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
const app = Vue.createApp({
+
watch:{
   data() {
+
   // it is allowed to watch computed properties
     return {
+
  result(value){
      counter: 0,
+
     const that = this;
    };
+
     setTimeout(function(){
  },
+
      console.log("timeout");
  methods:{
+
      that.counter = 0;
     plus(n){ this.counter = this.counter + n },
+
       return 0;
    minus(n){ this.counter = this.counter - n },
+
     },3000);
    updateName(event){
 
       this.name = event.target.value
 
     }
 
 
   }
 
   }
});
+
}
 
 
app.mount('#events');
 
 
</syntaxhighlight>
 
</syntaxhighlight>
<syntaxhighlight lang="html5">
 
<section id="events">
 
  <h2>Events in Action</h2>
 
  <p> We can use expression in v-on:click or use a function from our methods object</p>
 
  <!-- CLICK EVENT -->
 
  <button v-on:click="plus(5)">Add 5</button>
 
  <button v-on:click="minus(5)">Substract 5</button>
 
  <p>Result: {{ counter }}</p>
 
  <!-- INPUT EVENT -->
 
  <input type="text" v-on:input="updateName">
 
  <p>Hello {{ name }}</p>
 
 
</section>
 
</syntaxhighlight>
 
===== v-on Shortcut =====
 
v-on: kann durch @ ersetzt werden.
 
v-on:click="plus(5)"
 
@:click="plus(5)"
 
 
==== $event ====
 
In Eventlistenern kann man automatisch auf das event Argument zugreifen, das der Browser automatisch mitliefert (siehe Beispiel oben). Wenn man allerdings selbst ein Argument übermittelt wird das Event Argument überschrieben. Man kann aber mit dem reservierten Argument $event trotzdem wieder auf das Event Objekt zugreifen:
 
  
 +
=== Toggle Classes ===
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
    updateName(event, lastName){
+
//...
      this.name = event.target.value + ' ' + lastName
+
data(){ return { boxSelected: false } },
    }
+
methods:{ toggleBox(){ this.boxSelected = !this.boxSelected; } }
</syntaxhighlight>
+
//...
<syntaxhighlight lang="html5">
 
      <input type="text" v-on:input="updateName($event,'Schlegel')">
 
      <p>Hello {{ name }}</p>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 
==== Event Modifiers ====
 
Es gibt verschiedene Event Modifier z.B. um sich ein event.preventDefault() zu sparen. Event Modifiers werden mit einem '.' an das Event im HTML angehängt
 
v-on:submit.prevent
 
 
https://vuejs.org/v2/guide/events.html#Event-Modifiers
 
===== Click Modifiers =====
 
v-on:click.right
 
v-on:click.middle
 
...
 
 
===== Key Modifiers =====
 
//.enter means fire only if ENTER Key is pressed
 
v-on:keyup.enter="confirmInput" //possible is all ctrl, shift, page-down...
 
  
 
<syntaxhighlight lang="html5">
 
<syntaxhighlight lang="html5">
<!--also multiple v-on handlers are possible-->
+
<div @click="selectBox()" class="box" :class="{ active : boxSelected }"></div>
<input type="text"  
 
  v-on:input="updateName"  
 
  v-on:keyup.enter="confirmName">
 
<p>Hello {{ confirmedName }}</p>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
=== Add and remove items to / from a list ===
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
 
const app = Vue.createApp({
 
const app = Vue.createApp({
 
   data() {
 
   data() {
     return {
+
     return {  
       name: '',
+
       enteredGoalValue: '',
       confirmedName: '',
+
       goals: []
    };
+
    };
 
   },
 
   },
   methods:{
+
   methods: {
     updateName(event, lastName){
+
     addGoal() {
       this.name = event.target.value
+
       this.goals.push(this.enteredGoalValue);
 +
      this.enteredGoalValue = '';
 
     },
 
     },
     confirmName(){
+
     removeGoal(i){
       this.confirmedName = this.name
+
      console.log("removeGoal " + i)
 +
       this.goals.splice(i,1); // splice 1 item at index i
 
     }
 
     }
 
   }
 
   }
 
});
 
});
app.mount('#events');
+
app.mount('#user-goals');
 +
</syntaxhighlight>
 +
 
 +
<syntaxhighlight lang="html5">
 +
  <section id="user-goals">
 +
      <h2>My course goals</h2>
 +
      <input type="text" v-model="enteredGoalValue" />
 +
      <button @click="addGoal">Add Goal</button>
 +
      <p v-if="goals.length === 0">No goals have been added yet - please start adding some!</p>
 +
      <ul v-else>
 +
        <li v-for="(goal, i) in goals" @click="removeGoal(i)" :key="[myID]">#{{i}} {{goal}}</li> // use a unique id for key attribute
 +
      </ul>
 +
    </section>
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Two way binding ===
+
=== Components ===
Bei Input Feldern möchten wir oft einerseits
+
==== Component Todos ====
1. Eine data Property mit mit der User Eingabe setzen
+
'''Mit CLI'''
2. Eine data Property auslesen und im value Attribut setzen.  
+
* myComponent.vue Datei erstellen
Das bedeutet wir müssen das Input Feld auf zwei Wegen verbinden
+
* In main.js Import und component Funktion
 +
* In App.vue Import
 +
* In myComponent.vue props, emits festlegen
 +
* In App.vue emits als v-on nutzen
 +
* In App.vue props als Argumente übergeben
 +
==== Basic Component ====
 +
Parent
 +
<syntaxhighlight lang="html5">
 +
<template>
 +
    <h1>My App</h1>
 +
    <ul>
 +
        <learning-resource v-for="res in storedResources"
 +
            :key="res.id"
 +
            :title="res.title"
 +
            :description="res.description"
 +
            :link="res.link">
 +
        </learning-resource>
 +
    </ul>
 +
</template>
 +
<script>
 +
import LearningResource from './components/learning-resources/LearningResource.vue'
  
==== Beispiel Reset Button ====
+
export default {
Das Input Feld bekommt 2 Binds
+
    components:{
 +
        LearningResource,
 +
    },
 +
    data(){
 +
        return {
 +
            storedResources: [
 +
                { 
 +
                    id: 'official-guide',
 +
                    title: 'Official Guide',
 +
                    description: 'The official Vue.js documentation',
 +
                    link: 'https://vuejs.org'
 +
                },
 +
                {
 +
                    id: 'google',
 +
                    title: 'Google',
 +
                    description: 'Search for other things...',
 +
                    link: 'https://google.de'
 +
                },
 +
            ]
 +
        }
 +
    }
 +
}
 +
</script>
 +
</syntaxhighlight>
  
1. Value Attribut wird an das "name" Property gebuden.
+
Child
  2. Input Event wird an die Funktion "setName" gebunden.
+
<syntaxhighlight lang="html5">
 +
<template>
 +
<li>
 +
  <h3> {{ title }} </h3>
 +
  <p> {{ description }}  </p>
 +
  <nav>
 +
    <a :href="link">View resource</a>
 +
  </nav>
 +
</li>
 +
</template>
 +
<script>
 +
export default {
 +
    props: ['title', 'description', 'link']
 +
}
 +
</script>
 +
</syntaxhighlight>
  
Wird von irgendwoher (in unserem Fall vom Reset Knopf) die Eigenschaft "name" verändert, so wird auch der value im Input automatisch verändert.
+
=== Slots ===
In Vanilla JS müßten wir alle Stellen in denen name gesetzt ist von Hand zurücksetzen müssen.
+
Basic Slot
  
 +
'''App.vue'''
 
<syntaxhighlight lang="html5">
 
<syntaxhighlight lang="html5">
<input type="text" v-bind:value="name" v-on:input="setName($event)">
 
<p>Your Name: {{ name }}</p>
 
<button v-on:click="reset()">Reset</button>
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 +
=== Send Receive REST Data ===
 +
Das folgende Beispiel bezieht und sendet JSON Daten von / zu einer Firebase Datenbank. Das Prinzip läßt sich auf alle REST Schnittstellen adaptieren.
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
//...
+
loadExperiences() {
  data() {
+
      this.isLoading = true;
    return { name: '' };
+
      this.error = null;
  },
+
      fetch('https://vue-course-http-01-default-rtdb.firebaseio.com/surveys.json')
  methods: {
+
        .then( (response) => {
    setName(event) { this.name = event.target.value; },
+
          // is executed when data arrived. Arg response is provided automatically.
    reset() { this.name = ''; }
+
          if (response.ok) {
  }
+
            return response.json(); // parse json data and return promise
//...
+
          }
 +
        })
 +
        .then( (data) => {
 +
          // executed when promise returned
 +
          // hint if we would use function(data) instead of arrow function
 +
          // the keyword this would not work
 +
          this.isLoading = false;
 +
          console.log('Received Data: ');
 +
          console.log(data);
 +
          const results = [];
 +
          for( const id in data){
 +
            results.push({ id: id, name: data[id].name, rating: data[id].rating})
 +
          }
 +
          this.results = results;
 +
        })
 +
        .catch(
 +
          // catch will be triggered when an error in any of the previous promises occurs
 +
          // argument error is provided automatically in the function
 +
          (error) => {
 +
            console.log('Error' + error);
 +
            this.isLoading = false;
 +
            this.error = 'Failed to fetch data: '  + error;
 +
          }
 +
        );
 +
    }
 
</syntaxhighlight>
 
</syntaxhighlight>
===== v-model two-way-binding =====
 
Two Way Binding bedeutet also die Kombination aus '''Eventhandling''' (Ereignisbehandlung = Aufrufen einer Funktion bei einem Event) '''und Databinding''' (Die Bindung des Wertes an eine Eigenschaft). Dieser Fall tritt sehr oft auf, daher gibt es für dieses Muster eine eigene Direktive.
 
  
Statt
+
<syntaxhighlight lang="javascript">
<input type="text" v-bind:value="name" v-on:input="setName($event)">
+
submitSurvey() {
schreiben wir nur
+
      if (this.enteredName === '' || !this.chosenRating) {
<input type="text" v-model="name">
+
        this.invalidInput = true;
'''Die Funktion setName die wir oben haben entfällt komplett.''' Denn die Eigenschaft "name" wird mit two-way-binding sowohl gesetzt als auch abgerufen. Im Two Way Binding ist das Model also mit Getter und Setter enthalten.  
+
        return;
 +
      }
 +
      this.invalidInput = false;
  
=== Computed Properties ===
+
      // this.$emit('survey-submit', {
Wir können Interpolations auch mit Funktionen nutzen:
+
      //  userName: this.enteredName,
<pre> {{ myFunction() }} </pre>
+
      //  rating: this.chosenRating,
Das kann allerdings in '''Performance Problemen''' enden. '''Da Vue nicht weiß welche Properties in der Funktion angepasst werden''' führt es diese Funktion bei jeder Änderung von irgendwelchen Properties (in data) aus, auch wenn das gar nicht notwendig ist. Um das zu umgehen gibt es neben ''data'' und ''methods'' noch ein drittes Konigurationsobjekt nämlich ''computed''.
+
      // });
 +
      this.error = null;
 +
      fetch('https://vue-course-http-01-default-rtdb.firebaseio.com/surveys.json', {
 +
        method: 'POST',
 +
        headers: {
 +
          'Content-Type': 'application/json'
 +
        },
 +
        body: JSON.stringify({
 +
          name: this.enteredName,
 +
          rating: this.chosenRating
 +
        }),
 +
      })
 +
      .then( response => {
 +
        if (response.ok) {
 +
          console.log("We got a valid response from server: " + response);
 +
        }else{
 +
          throw new Error('Could not save data');
 +
          // this creates new Error Object which we receive in catch()
 +
        }
 +
      })
 +
      .catch(error => {
 +
        console.log(error);
 +
        this.error = error.message;
 +
      });
  
Im computed Objekt können wir wie in methods '''Funktionen definieren'''. Diese Funktionen werden aber '''benutzt wie Eigenschaften'''. Daher sollte man sie auch wie Properties benennen also z.b. nicht renderFullname sondern fullname. Im HTML Code darf sich auch nicht aufgerufen werden sondern man zeigt nur auf die Funktion also '''NICHT {{ fullname() }} sondern nur {{ fullname }}'''.
+
      this.enteredName = '';
Per Konzept ruft Vue diese Funktionen dann selbst auf wenn notwendig.
+
       this.chosenRating = null;
 
==== method oder computed ? ====
 
computed
 
* immer dann wenn etwas gerendert werden soll
 
* wenn man die Funktion wie eine Eigenschaft nutzt
 
* rufe niemals eine computed method auf
 
 
 
method
 
* Wenn eine Methode immer ausgeführt werden soll sobald eine Änderung eintritt. Dann kannst du eine Methode direkt in eine Interpolation schreiben.
 
* Für bindings. Also Funktionen die bei Events aufgerufen werden.
 
* Tatsächliche Funktionalität die von anderen Methoden aufgerufen wird.
 
 
 
=== Watchers ===
 
Watchers sind ein 4. Konfigurationsobjekt und haben Ähnlichkeit mit den Computed Properties. Ein Watcher überwacht die Änderung einer Eigenschaft und wird dann ausgeführt.
 
Eine Watcherfunktion bekommt immer den Namen einer Eigenschaft.
 
 
 
<syntaxhighlight lang="javascript">
 
data{
 
  counter: 0;
 
},
 
watch{
 
    counter(value){
 
       if (value > 50) this.counter = 0;
 
 
     }
 
     }
}
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Wann immer sich die Eigenschaft counter verändert wird die Funktion counter() aufgerufen.
+
=== Utilities / nützliche Funktionen ===
 +
Normale JavaScript Funktionen die oft nützlich im Zusammenhang mit Vue sind.
  
Der Watcher Funktion kann automatisch der aktuellste und der vorigen Wert der Eigenschaftsvariablen übergeben werden.
+
Siehe [[JavaScript - Snippets]]
counter(oldValue, newValue){ ... }
 
  
Die Stärken von Watchern sind die Überwachung von Zuständen. Du nutzt sie immer dann wenn etwas ausgeführt werden soll wenn ein bestimmter Zustand eintrifft. Computed Properties haben ihre Stärke eher dann wenn einfach nur Werte bei jedem Event verändert werden müssen aber ein v-model nicht ausreicht.
+
==== Arrays ====
 +
===== Elemente hinzufügen / entfernen =====
 +
Gegeben ist ein Array items in der Art
 +
[{id: 1, name: Anton, isFavourite: true}, {id: 2, name: Berta},...]
 +
<syntaxhighlight lang="javascript">
  
=== methods vs computed vs watch ===
+
// add to end of array
''' Einsatzbereich von Methods '''
+
this.friends.push(newFriend)
* '''Wenn in Interpolations''' {{ functionName() }} werden Sie bei '''jeder Änderung, egal welcher Property''' ausgeführt. -> Nur bei Aufgaben die bei jeder Änderung ausgeführt werden sollen
 
* '''Aufgaben die von Events via v-bind aufgerufen werden. Also bei der '''Ereignisbehandlung'''.'''
 
* Allgemeine Funktionen ohne bestimmten Bezug zu einem Event o.ä.
 
  
''' Einsatzbereich von Computed Properties '''
+
// add to start of array
* Aufgaben die bei '''Änderungen von einer oder mehrere Eigenschaften ausgeführt werden, aber nicht bei allen.
+
this.friends.unshift(newFriend)
* '''Aufgaben die von mehreren Eigenschaften abhängen''' (z.B. Vor- ODER Nachname wird geändert). Hier kann man mit CP Code im Vergleich zu Watchern sparen.
 
* Bessere Performance wenn nicht alle Eigenschaften berücksichtigt werden müssen (im Vergleich zu Methods).
 
* werden nicht direkt in Interpolations aufgerufen sondern nur referenziert ( {{ myComputed }} aber nicht {{ myComputed() }}
 
  
 
+
// delete item from array via id (will not work with provide/inject data in components)
'''Einsatzbereich von Watchern'''
+
deleteItem(id){
* Aufgaben die '''bei bestimmten Ereignissen''' ausgerführt werden. Sprich: Eigenschaften auf einen bestimmten Zustand hin überwachen.
+
  this.items = this.items.filter( item => item.id !== sarchId)
* Bei einem bestimmten Zustand einen http Request ausführen
+
  // filter( filterFunction ) uses filterFunction for every item in items.
* Timer starten, resetten
+
  // If filterFunction returns true the item is kept. item.id !== id returns true for every
* Etwas in localStorage speichern
+
  // item which has NOT the id
* Werden nicht direkt im Template verwendet (nur die Property)
+
}
* Können Properties aber auch computed Properties überwachen
+
// this works because we change the array directly
 
+
deleteItem(id){
=== Dynamic Styling ===
+
  const itemIndex = this.items.findIndex(item => item.id === id)
 
+
   this.items.splice(resIndex, 1);
==== Style Attribut ====
 
In den Attributen style und class erlaubt Vue eine besondere Syntax. Man kann ein Objekt mit einem Style direkt mit v-bind (oder :) einsetzen.
 
v-bind:style="{color:green}"
 
bei Eigenschaften mit Bindestrich kann man camelCase verwenden:
 
v-bind:style="'border-color': red"
 
v-bind:style="borderColor: red"
 
Auch Ausdrücke sind wie immer bei Vue erlaubt. Hier ein Beispiel (beachte auch v-bind: wird durch : ersetzt)
 
:style="{borderColor: selectedBoxA ? 'red' : '#ccc' }"
 
In diesem Beispiel gehen wir davon aus dass wir eine Property 'selectedBoxA haben, die auf true oder false steht.
 
 
 
==== Class Attribut ====
 
Vue kann auch eine Klasse setzten. Das ist in der Regel auch die bessere Vorgehensweise, da man Inline Styles schlecht überschreiben kann. Auch hier sind Ausdrücke möglich. Wir gehen in den Beispielen davon aus, dass wir eine Eigenschaft '''selectedBoxA''' haben die true oder false ist und eine Funktion ''selectBox()'' die für uns diese Eigenschaft auf true setzen kann.
 
:class="selectedBoxA ? 'active demo' : 'demo'"
 
<syntaxhighlight lang="html5">
 
<div @click="selectBox('A')" :class="selectedBoxA ? 'active demo' : 'demo'"></div>
 
</syntaxhighlight>
 
Auch für class gibt es eine spezielle Syntax die das Leben einfacher macht:
 
<syntaxhighlight lang="html5">
 
<div @click="selectBox('A')" :class="{demo: true, active: boxSelectedA}"></div>
 
</syntaxhighlight>
 
Vue akzeptiert ein Objekt in dem man einfach key value Paare übergibt. Ist der value true wird die Klasse gesetzt. wenn also boxSelectedA true ist wird die Klasse active gesetzt. Demo wird immer gessetzt.
 
 
 
===== class + :class =====
 
Noch einfacher wird es, wenn man auch das class Attribut und das v-bind class Attribut zusammen einsetzt. Vue merged dann das dynamisch gebundene mit dem statischen class Attribut.
 
<syntaxhighlight lang="html5">
 
<div @click="selectBox('A')" class="demo" :class="{active: boxSelectedA}"></div>
 
</syntaxhighlight>
 
 
 
===== Class Object aus computed property =====
 
Du kannst auch die Logik komplett auslagern. Dazu gibst du das Object am Besten aus einem computed Property zurück:
 
 
 
<syntaxhighlight lang="html5">
 
<div @click="selectBox('A')" class="demo" :class="boxAClasses"></div>
 
</syntaxhighlight>
 
<syntaxhighlight lang="javascript">
 
computed:{
 
   boxAClasses(){
 
    return{ active: this.boxSelectedA }
 
  }
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Hier kann man auch komplexere Logik abbilden.
 
  
===== Array Schreibweise / mehrere Class Objekte =====
+
===== Finden und Suchen =====
Du kannst auch mehrere Objekte nutzen. Dazu kommen Sie in ein Array:
 
:class="['demo', {active: boxSelectedA}]"
 
 
 
=== Conditions ===
 
==== v-if / v-else / v-else-if ====
 
In data() haben wir ein array definiert:
 
goals: []
 
<syntaxhighlight lang="html">
 
<p v-if="goals.length === 0">No goals have been added yet - please start adding some!</p>
 
<ul v-else>
 
  <li>Goal</li>
 
</ul>
 
</syntaxhighlight>
 
Wenn goals Inhalt hat wird die Liste angezeigt. Das ist hier natürlich nur mäßig sinnvoll, da wir die Liste hier nicht dynamisch füllen, erklärt aber das Prinzip.
 
 
 
Außerdem gibt es noch v-else-if das man genauso wie das v-else nach v-if einbauen kann. Funktioniert wie in anderen Sprachen.
 
 
 
== Snippets ==
 
=== Starter ===
 
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
const app = Vue.createApp({
+
// find in array and change prop
   data(){
+
const identifiedItem = this.items.find(
    return{
+
   (item) => item.id === searchId // the same as function(friend){return friend.id...}
    }
+
)
  },
+
// filter(callback) - callback is executed on every array (array item) first item match is returned
  methods:{
+
identifiedItem.isFavourite = !identifiedItem.isFavourite
  },
+
// identifiedItem is a proxy connected to the original items array.
  computed:{
+
// thus why we can modify identifiedItems and items will be altered too
  },
 
  watch:{
 
  }
 
});
 
app.mount('#assignment');
 
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Using this in a submethod i.e. Timer ===
+
===== Validierung =====
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
watch:{
+
submitData(){
  // it is allowed to watch computed properties
+
  const enteredTitle = this.$refs.titleInput.value;
  result(value){
+
  if (enteredTitle.trim() === ''){
    const that = this;
+
    this.inputIsValid = false;
    setTimeout(function(){
+
    return;
      console.log("timeout");
 
      that.counter = 0;
 
      return 0;
 
    },3000);  
 
  }
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
=== Toggle Classes ===
+
===== Sonstiges =====
<syntaxhighlight lang="javascript">
+
''Underscore Argumente'' - nutze diese wenn du Argumente, die automatisch bereitgestellt werden nicht benötigst. Dann meckert der Compiler nicht:
//...
+
scrollBehavior(to, from, savedPosition){// compiler tells you that you don't use them}
data(){ return { boxSelected: false } },
+
scrollBehavior(_, _2, savedPosition){
methods:{ toggleBox(){ this.boxSelected = !this.boxSelected; } }
+
  console.log(savedPosition) // compiler does not complain :-)
//...
+
  }
</syntaxhighlight>
 
 
 
<syntaxhighlight lang="html5">
 
<div @click="selectBox()" class="box" :class="{ active : boxSelected }"></div>
 
</syntaxhighlight>
 

Aktuelle Version vom 9. Januar 2021, 02:00 Uhr

Links[Bearbeiten]

Vue.js
Vue - Basic Concepts
Vue CLI
Vue - Components

Snippets[Bearbeiten]

Starters[Bearbeiten]

const app = Vue.createApp({
  data(){
    return{
    }
  },
  methods:{
  },
  computed:{
  },
  watch:{
  }
});
app.mount('#assignment');

Starter mit main.js (CLI)[Bearbeiten]

import { createApp } from 'vue';
// Import Main App
import App from './App.vue';
// Import Global Components
import BaseBadge from './components/BaseBadge.vue';
import BaseCard from './components/BaseCard.vue'
// Create App Instance
const app = createApp(App);
// Register Components
app.component('base-badge', BaseBadge);
app.component('base-card', BaseCard)
// Mount App
app.mount('#app');

Using this in a submethod i.e. Timer[Bearbeiten]

watch:{
  // it is allowed to watch computed properties
  result(value){
    const that = this;
    setTimeout(function(){
      console.log("timeout");
      that.counter = 0;
      return 0;
    },3000); 
  }
}

Toggle Classes[Bearbeiten]

//...
data(){ return { boxSelected: false } },
methods:{ toggleBox(){ this.boxSelected = !this.boxSelected; } }
//...
<div @click="selectBox()" class="box" :class="{ active : boxSelected }"></div>

Add and remove items to / from a list[Bearbeiten]

const app = Vue.createApp({
  data() {
    return { 
      enteredGoalValue: '',
      goals: []
     };
  },
  methods: {
    addGoal() {
      this.goals.push(this.enteredGoalValue);
      this.enteredGoalValue = '';
    },
    removeGoal(i){
      console.log("removeGoal " + i)
      this.goals.splice(i,1); // splice 1 item at index i 
    }
  }
});
app.mount('#user-goals');
   <section id="user-goals">
      <h2>My course goals</h2>
      <input type="text" v-model="enteredGoalValue" />
      <button @click="addGoal">Add Goal</button>
      <p v-if="goals.length === 0">No goals have been added yet - please start adding some!</p>
      <ul v-else> 
        <li v-for="(goal, i) in goals" @click="removeGoal(i)" :key="[myID]">#{{i}} {{goal}}</li> // use a unique id for key attribute
      </ul>
    </section>

Components[Bearbeiten]

Component Todos[Bearbeiten]

Mit CLI

  • myComponent.vue Datei erstellen
  • In main.js Import und component Funktion
  • In App.vue Import
  • In myComponent.vue props, emits festlegen
  • In App.vue emits als v-on nutzen
  • In App.vue props als Argumente übergeben

Basic Component[Bearbeiten]

Parent

<template>
    <h1>My App</h1>
    <ul>
        <learning-resource v-for="res in storedResources" 
            :key="res.id"
            :title="res.title"
            :description="res.description"
            :link="res.link">
        </learning-resource>
    </ul>
</template>
<script> 
import LearningResource from './components/learning-resources/LearningResource.vue'

export default {
    components:{
        LearningResource,
    },
    data(){
        return {
            storedResources: [
                {   
                    id: 'official-guide',
                    title: 'Official Guide',
                    description: 'The official Vue.js documentation',
                    link: 'https://vuejs.org'
                },
                {
                    id: 'google',
                    title: 'Google',
                    description: 'Search for other things...',
                    link: 'https://google.de'
                },
            ]
        }
    }
}
</script>

Child

<template>
<li>
  <h3> {{ title }} </h3>
  <p>  {{ description }}  </p>
  <nav>
    <a :href="link">View resource</a>
  </nav>
</li>
</template>
<script>
export default {
    props: ['title', 'description', 'link']
}
</script>

Slots[Bearbeiten]

Basic Slot

App.vue

Send Receive REST Data[Bearbeiten]

Das folgende Beispiel bezieht und sendet JSON Daten von / zu einer Firebase Datenbank. Das Prinzip läßt sich auf alle REST Schnittstellen adaptieren.

loadExperiences() {
      this.isLoading = true;
      this.error = null;
      fetch('https://vue-course-http-01-default-rtdb.firebaseio.com/surveys.json')
        .then( (response) => { 
          // is executed when data arrived. Arg response is provided automatically.
          if (response.ok) {
            return response.json(); // parse json data and return promise
          }
        })
        .then( (data) => {
          // executed when promise returned
          // hint if we would use function(data) instead of arrow function 
          // the keyword this would not work
          this.isLoading = false;
          console.log('Received Data: ');
          console.log(data);
          const results = [];
          for( const id in data){
            results.push({ id: id, name: data[id].name, rating: data[id].rating})
          }
          this.results = results;
        })
        .catch(
          // catch will be triggered when an error in any of the previous promises occurs
          // argument error is provided automatically in the function
          (error) => {
            console.log('Error' + error);
            this.isLoading = false;
            this.error = 'Failed to fetch data: '  + error;
          }
        );
    }
submitSurvey() {
      if (this.enteredName === '' || !this.chosenRating) {
        this.invalidInput = true;
        return;
      }
      this.invalidInput = false;

      // this.$emit('survey-submit', {
      //   userName: this.enteredName,
      //   rating: this.chosenRating,
      // });
      this.error = null;
      fetch('https://vue-course-http-01-default-rtdb.firebaseio.com/surveys.json', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          name: this.enteredName,
          rating: this.chosenRating
        }),
      })
      .then( response => {
        if (response.ok) {
          console.log("We got a valid response from server: " + response);
        }else{
          throw new Error('Could not save data'); 
          // this creates new Error Object which we receive in catch()
        }
      })
      .catch(error => {
        console.log(error);
        this.error = error.message;
      });

      this.enteredName = '';
      this.chosenRating = null;
    }

Utilities / nützliche Funktionen[Bearbeiten]

Normale JavaScript Funktionen die oft nützlich im Zusammenhang mit Vue sind.

Siehe JavaScript - Snippets

Arrays[Bearbeiten]

Elemente hinzufügen / entfernen[Bearbeiten]

Gegeben ist ein Array items in der Art

[{id: 1, name: Anton, isFavourite: true}, {id: 2, name: Berta},...]
// add to end of array
this.friends.push(newFriend)

// add to start of array
this.friends.unshift(newFriend)

// delete item from array via id (will not work with provide/inject data in components)
deleteItem(id){
  this.items = this.items.filter( item => item.id !== sarchId)
  // filter( filterFunction ) uses filterFunction for every item in items.
  // If filterFunction returns true the item is kept. item.id !== id returns true for every
  // item which has NOT the id
}
// this works because we change the array directly
deleteItem(id){
  const itemIndex = this.items.findIndex(item => item.id === id)
  this.items.splice(resIndex, 1);
}
Finden und Suchen[Bearbeiten]
// find in array and change prop
const identifiedItem = this.items.find(
  (item) => item.id === searchId // the same as function(friend){return friend.id...}
)
// filter(callback) - callback is executed on every array (array item) first item match is returned
identifiedItem.isFavourite = !identifiedItem.isFavourite
// identifiedItem is a proxy connected to the original items array.
// thus why we can modify identifiedItems and items will be altered too
Validierung[Bearbeiten]
submitData(){
  const enteredTitle = this.$refs.titleInput.value;
  if (enteredTitle.trim() === ''){
    this.inputIsValid = false;
    return;
}
Sonstiges[Bearbeiten]

Underscore Argumente - nutze diese wenn du Argumente, die automatisch bereitgestellt werden nicht benötigst. Dann meckert der Compiler nicht:

scrollBehavior(to, from, savedPosition){// compiler tells you that you don't use them}
scrollBehavior(_, _2, savedPosition){
  console.log(savedPosition) // compiler does not complain :-)
 }