Vue - Snippets: Unterschied zwischen den Versionen

Aus Wikizone
Wechseln zu: Navigation, Suche
Zeile 7: Zeile 7:
 
=== Basics ===
 
=== Basics ===
 
  [[Vue - Basic Concepts]]
 
  [[Vue - Basic Concepts]]
 
  
 
== Components ==
 
== Components ==
Components sind '''wiederverwendbare Logikbausteine'''. Du kannst damit z.B. Logik so Kapseln, dass sie nicht durch andere Ereignisse oder Eigenschaften beeinflusst wird.
+
  [[Vue - Components]]
 
 
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 ==

Version vom 28. Dezember 2020, 11:45 Uhr

Links

Vue.js
Vue - Basic Concepts
Vue CLI

Vue Konzepte

Basics

Vue - Basic Concepts

Components

Vue - Components

Snippets

Starter

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

Using this in a submethod i.e. Timer

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

//...
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

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

Component Todos

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