Vue - Snippets: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
 
(23 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 3: Zeile 3:
 
  [[Vue - Basic Concepts]]
 
  [[Vue - Basic Concepts]]
 
  [[Vue CLI]]
 
  [[Vue CLI]]
 
+
  [[Vue - Components]]
== Vue Konzepte ==
 
=== Basics ===
 
  [[Vue - Basic Concepts]]
 
 
 
 
 
== Components ==
 
Components sind '''wiederverwendbare Logikbausteine'''. Du kannst damit z.B. Logik so Kapseln, dass sie nicht durch andere Ereignisse oder Eigenschaften beeinflusst wird.
 
 
 
Durch die Aufteilung einer großen App in kleinere Bausteine wird sie weniger fehleranfällig und leichter wartbar und die Entwicklung gerade bei größeren Apps effektiver.
 
 
 
Eine Component sieht im Template '''wie ein neuer Tag''' aus. Damit es keine '''Namenskonflikte''' gibt verwendest Du als Name am Besten eine Bezeichnung mit zwei Worten und Bindestrich <contact-details>. Dies kommmt bei normalen Tags nicht vor.
 
 
 
Definiert wird eine Komponente mit der component() Methode. Technisch gesehen ist eine Komponente eine '''App in einer App'''. Daher erzeugt man sie auch ganz ähnlich:
 
 
 
const app = Vue.createApp({ //... }) // creation of an app
 
app.component('single-contact', { //... }) // creation of a component in this app
 
 
 
Im ersten Argument definiert man den Namen über den später als Tag (<single-contact>) zugegriffen werden kann. Im zweiten Argument übergibt man ein Objekt, dass wiederum eigene data, methods... Objekte enthalten kann die aber nur für diese Komponente gelten.
 
 
 
=== Component Template ===
 
Die Component ist also eine Art Mini-App in der Hauptapp. Sie benötigt wie eine App ein Template. Es gibt mehrere Möglichkeiten das Template zu übergeben.
 
 
 
==== template Object ====
 
<syntaxhighlight lang="javascript">
 
app.component('friend-contact', {
 
    template: `
 
    <li>
 
        <h2>{{friend.name}}</h2>
 
        <button @click="toggleDetails()">Show Details</button>
 
        <ul v-if="detailsVisible">
 
            <li><strong>Phone:</strong> {{friend.phone}} </li>
 
            <li><strong>Email:</strong> {{friend.email}} </li>
 
        </ul>
 
    </li>
 
    `,// backticks allow multiline code
 
</syntaxhighlight>
 
 
 
=== Single File Components mit Vue CLI ===
 
Wenn man größere Apps bauen und effektiv mit Components arbeiten möchte hilft das Vue CLI und ein Development Setup mit Node.js und npm. Die folgenden Beispiele nutzen Single File Components. Schau unter
 
[[Vue CLI]]
 
nach wenn du nicht weißt wie man ein solches Setup aufbaut.
 
 
 
=== Component Communication ===
 
==== Parent - Child Communication mit props ====
 
https://v3.vuejs.org/guide/component-props.html
 
 
 
'''Mit props sendest Du Daten von der Parent App an die Child Component.'''
 
 
 
'''App.vue - <template> der Eltern App.'''
 
<syntaxhighlight lang="html5>
 
<ul>
 
        <friend-contact
 
        name="Stephan"
 
        phone-number="123"
 
        email-address="my@email.tld">
 
        </friend-contact>
 
        <friend-contact
 
        name="Finn"
 
        phone-number="345"
 
        email-address="my@mymail.tld">
 
        </friend-contact>
 
    </ul>
 
</syntaxhighlight>
 
 
 
'''FriendContact.vue - <script> - Child App'''
 
<syntaxhighlight lang="javascript">
 
props:[
 
  'name', 'phoneNumber', 'emailAddress'
 
],
 
</syntaxhighlight>
 
 
 
'''FriendContact.vue - <template>'''
 
<syntaxhighlight lang="html5>
 
  <h2>{{name}}</h2>
 
  <button @click="toggleDetails"> {{detailsVisible ? 'Hide' : 'Show'}} Details </button>
 
  <ul v-if="detailsVisible">
 
    <li><strong>Phone: </strong>{{phoneNumber}}</li>
 
    <li><strong>Email: </strong>{{emailAddress}}</li>
 
  </ul>
 
</syntaxhighlight>
 
 
 
Das '''props Objekt in der Komponente''' definiert welche Attribute die Komponente akzeptiert und erwartet. Im der Parent App übergibt man die Daten für diese props einfach als Attribute.
 
* werden in props der component als ''camelCase'' , stehen aber als ''kebab-case'' im HTML zur Verfügung (du solltest sie auch so verwenden)
 
* props stehen mit ''this.myProp'' auch in Methoden etc. zur Verfügung
 
 
 
===== Unidirectional Data Flow =====
 
Daten die an die Kind App übertragen werden '''dürfen nicht mehr verändert werden'''.
 
 
 
Beispiel: Wenn Du eine prop isFavourite hast und Sie über einen Toggle Button verändern willst kannst du das nicht in der Child App verändern weil die Daten nur von Parent nach Child fließen dürfen. Vue gibt einen Fehler aus.
 
 
 
Es gibt zwei Strategien die man anwenden kann:
 
* Daten zurück an Parent übertragen (siehe unten)
 
* Daten nutzen um eine Komponentenvariable zu initialisieren und diese verändern.
 
 
 
===== Props Object =====
 
Anstatt einem Array kann man auch Objekte übertragen. Darin kann man einige '''Zusatzinformationen''' unterbringen. Das ist vor allem bei großen Projekten vlt. mit mehreren Programmierern sinnvoll um Komponenten zuverlässiger zu machen. Die zusätzlichen Properties sind festgelegt: type, required
 
 
 
<syntaxhighlight lang="javascript">
 
props:['name', 'phoneNumber', 'emailAddress'], // Array
 
props:{ name: String, phoneNumber: String, emailAddress: String, }, // Object mit Type
 
props:{
 
  name: { type: String, required: false},
 
  isFavourite: {
 
    type: String,
 
    required: false,
 
    default: '0', // could also be a function: function(){ return: '1'},
 
    validator: function(value){ return value === '0' || value === '1' }
 
  }
 
}
 
</syntaxhighlight>
 
Mit den zusätzlichen Infos kann vue in der Konsole Fehler ausgeben oder du kannst selber Auswertungen der Daten in der Komponente vornehmen. Erlaubte Types sind:
 
String, Number, Boolean, Array, Object, Date, Function, Symbol
 
But type can also be any constructor function (built-in ones like Date or custom ones).
 
 
 
===== Props mit dynamischen Daten nutzen =====
 
Um Props dynamisch zu nutzen kann man sie einfach mit v-bind (oder : ) an Daten binden und mit v-for durchlaufen. Plicht ist jetzt das key Attribut in die man eine eindeutige id geben muss.
 
 
 
'''App.vue:'''
 
<syntaxhighlight lang="javascript">
 
//...
 
friends:[
 
{
 
  id: 'yvonne',
 
  name: 'Yvonne Oßwald',
 
  phone: '49 123 456',
 
  email: 'post@yvonneosswals.de',
 
  isFavourite: false
 
},
 
//...
 
</syntaxhighlight>
 
 
 
'''in <template>'''
 
<syntaxhighlight lang="html5">
 
<ul>
 
  <friend-contact
 
    v-for="friend in friends"
 
    :key="friend.id"
 
    :name="friend.name"
 
    :phone-number="friend.phone"
 
    :email-address="friend.email">
 
  </friend-contact>
 
</ul>
 
</syntaxhighlight>
 
 
 
Die Komponente
 
<syntaxhighlight lang="html5">
 
<li>
 
        <h2>{{name}} {{friendIsFavourite ? '(*)' : ''}}</h2>
 
        <button @click="toggleFavourite">Toggle Favourite</button>
 
        <button @click="toggleDetails"> {{detailsVisible ? 'Hide' : 'Show'}} Details </button>
 
        <ul v-if="detailsVisible">
 
            <li><strong>Phone: </strong>{{phoneNumber}}</li>
 
            <li><strong>Email: </strong>{{emailAddress}}</li>
 
        </ul>
 
    </li>
 
</syntaxhighlight>
 
<syntaxhighlight lang="javascript">
 
props:{
 
        name: String,
 
        phoneNumber: String,
 
        emailAddress: String,
 
        isFavourite: {type: Boolean, required: false, default: false}
 
    },
 
</syntaxhighlight>
 
 
 
===== Fallthrough props =====
 
Angenommen Du hast eine BaseButton.vue Komponente ohne definierte Props.
 
'''Im Parent kannst Du trotzdem Attribute und Events''' nutzen...
 
<base-button type="submit" @click="doSomething">Click me</base-button>
 
... und diese dann in der Komponente auswerten.
 
Dafür hat vue ein spezielles $attrs Objekt auf das Du mit
 
this.$attrs
 
zugreifen kannst. Dies kann z.b. bei Komponenten mit nur geringer Funktionalität nützlich sein, die eher zur reinen Ausgabe dienen.
 
 
 
===== Alle props in einem Objekt binden =====
 
Angenommen deine Komponente sieht etwas so aus:
 
 
 
'''UserData.vue'''
 
<syntaxhighlight lang="html5">
 
<template>
 
  <h2>{‌{ firstname }} {‌{ lastname }}</h2>
 
</template>
 
 
<script>
 
  export default {props: ['firstname', 'lastname'] }
 
</script>
 
</syntaxhighlight>
 
 
 
Anstatt alle Props einzeln zu übertragen kannst du auch ein Übergeordnetes Objekt definieren und dieses übertragen.
 
 
 
'''App.vue'''
 
<syntaxhighlight lang="javascript">
 
data() {
 
  return {person: { firstname: 'Max', lastname: 'Muster' } };
 
}
 
</syntaxhighlight>
 
<syntaxhighlight lang="html5">
 
<!-- Einzelne Attribute binden -->
 
<user-data :firstname="person.firstname" :lastname="person.lastname"></user-data>
 
<!-- Alternativ: übergeordnetes Attribut binden (Achtung person ist value des Attributes -->
 
<user-data v-bind="person"></user-data>
 
</syntaxhighlight>
 
 
 
==== Child - Parent Communication mit custom Events ($emit) ====
 
 
 
'''Mit custom Events sendest du Daten von einer Komponente zurück an die Parent app.'''
 
Parent App -- [v-bind data] --> Component -- [custom Event data] -->
 
* Custom Events definierst du mit $emit in der Komponente
 
* In der Parent App nutzt du das Event im HTML Teil mit v-on
 
 
 
Wenn in einer Komponente Daten verändert werden muss man sie zurück zur Elternkomponente übertragen. Das Ändern der Props ist wegen dem unidirectional dataflow nicht erlaubt.
 
 
 
'''$emit()'''
 
 
 
Um Daten zurück zu senden können wir custom Events nutzen. Dazu gibt es die $emit Funktion
 
this.$emit('event-name', argument1, argument2, ...) // always use kebab-case
 
# in der Component in einer method this.$emit aufrufen z.b. this.$emit('toggle-state', this.id)
 
## id ist meist sinnvoll damit in der Parent App der Datensatz zugeordnet werden kann.
 
# im HTML der Eltern App einen v-on mit diesem Event anlegen z.B. @toggle-state="toggleState"
 
# in der gebundenen Methode in der Eltern App verarbeiten z.b. toggleState(id){ //ie. store in db }
 
 
 
Beispiel - es soll ein isFavourite Datum aus der Kindkomponente (Friendcontact.vue) gesetzt werden. Mit Klick auf den Button wird ein CustomEvent gesendet. Dieses wird in der Parent App ausgewertet und in den Daten gesezt. Über das v-bind in der Parent App wird es zurück in die h2 der Kind Komponente gesendet und diese aktualisiert.
 
 
 
'''FriendContact.vue'''
 
<syntaxhighlight lang="html">
 
<template>
 
    <li>
 
        <h2>{{name}} {{isFavourite ? '(*)' : ''}}</h2>
 
        <button @click="toggleFavourite">Toggle Favourite</button>
 
        <!-- ... -->
 
    </li>
 
</template>
 
 
 
<script>
 
export default {
 
    props:{
 
        id: {type: String, required: true},
 
        //...
 
        isFavourite: {type: Boolean, required: false, default: false}
 
    },
 
    emits:['toggle-favourite'], // emits object is optional and just for documentation purpose
 
    methods:{
 
        toggleFavourite(){
 
            this.$emit('toggle-favourite', this.id);
 
        }
 
    }
 
   
 
}
 
</script>
 
</syntaxhighlight>
 
'''App.vue'''
 
<syntaxhighlight lang="html">
 
<template>
 
<section>
 
    <header><h1>My Friends</h1></header>
 
    <ul>
 
        <friend-contact
 
        v-for="friend in friends"
 
        :key="friend.id"
 
        :id="friend.id"
 
        :name="friend.name"
 
        //...
 
        :is-favourite="friend.isFavourite"
 
        @toggle-favourite="toggleFavouriteState">
 
        </friend-contact>
 
    </ul>
 
</section>
 
</template>
 
 
 
<script>
 
import FriendContact from './components/FriendContact.vue'
 
export default {
 
  components: {
 
      FriendContact
 
    },
 
    data(){
 
        return {
 
            friends:[
 
                {
 
                    id: 'yvonne',
 
                    name: 'Yvonne Oßwald',
 
                    phone: '49 123 456',
 
                    email: 'post@yvonneosswals.de'
 
                },
 
                {
 
                    id: 'finn',
 
                    name: 'Finn Schlegel',
 
                    phone: '49 456 789',
 
                    email: 'post@finnschlegel.de' ,
 
                    isFavourite: true
 
                },
 
            ]
 
        }
 
    },
 
    methods:{
 
        toggleFavouriteState(friendId){
 
            const identifiedFriend = this.friends.find(
 
                (friend) => friend.id === friendId // eq: function(friend){return friend.id...}
 
                // this callback is executed on every friend (array item)
 
                // first item match is returned
 
            )
 
            // identifiedFriend is a proxy which handles the origin array element of friends array
 
            // thats why we can modify identifiedFriend and friends will be altered too
 
            // console.log('identifiedFriend: ' + identifiedFriend.id)
 
            identifiedFriend.isFavourite = !identifiedFriend.isFavourite
 
        }
 
    }
 
}
 
</script>
 
</syntaxhighlight>
 
  
 
== Snippets ==
 
== Snippets ==
=== Starter ===
+
=== Starters ===
 
<syntaxhighlight lang="javascript">
 
<syntaxhighlight lang="javascript">
 
const app = Vue.createApp({
 
const app = Vue.createApp({
Zeile 331: Zeile 21:
 
});
 
});
 
app.mount('#assignment');
 
app.mount('#assignment');
 +
</syntaxhighlight>
 +
 +
==== Starter mit main.js (CLI) ====
 +
<syntaxhighlight lang="javascript">
 +
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');
 +
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Zeile 404: Zeile 112:
 
* In App.vue emits als v-on nutzen
 
* In App.vue emits als v-on nutzen
 
* In App.vue props als Argumente übergeben
 
* 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'
 +
 +
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>
 +
</syntaxhighlight>
 +
 +
Child
 +
<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>
 +
 +
=== Slots ===
 +
Basic Slot
 +
 +
'''App.vue'''
 +
<syntaxhighlight lang="html5">
 +
</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">
 +
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;
 +
          }
 +
        );
 +
    }
 +
</syntaxhighlight>
 +
 +
<syntaxhighlight lang="javascript">
 +
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;
 +
    }
 +
</syntaxhighlight>
 +
 +
=== Utilities / nützliche Funktionen ===
 +
Normale JavaScript Funktionen die oft nützlich im Zusammenhang mit Vue sind.
 +
 +
Siehe [[JavaScript - Snippets]]
 +
 +
==== 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">
 +
 +
// 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);
 +
}
 +
</syntaxhighlight>
 +
 +
===== Finden und Suchen =====
 +
<syntaxhighlight lang="javascript">
 +
// 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
 +
</syntaxhighlight>
 +
 +
===== Validierung =====
 +
<syntaxhighlight lang="javascript">
 +
submitData(){
 +
  const enteredTitle = this.$refs.titleInput.value;
 +
  if (enteredTitle.trim() === ''){
 +
    this.inputIsValid = false;
 +
    return;
 +
}
 +
</syntaxhighlight>
 +
 +
===== Sonstiges =====
 +
''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 :-)
 +
  }

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 :-)
 }