| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung |
| de:modul:m291:learningunits:lu10:theorie:a_components [2026/05/02 22:24] – gkoch | de:modul:m291:learningunits:lu10:theorie:a_components [2026/05/10 20:32] (aktuell) – gkoch |
|---|
| ===== Lernziele ===== | ===== Lernziele ===== |
| |
| * Sie können ein Array of Objects mit ''ref()'' erstellen und im Template ausgeben. | * Sie können ein Array of Objects erstellen und im Template ausgeben. |
| * Sie können mit ''v-for'' dynamisch über ein Array iterieren und Komponenten rendern. | * Sie können mit ''v-for'' dynamisch über ein Array iterieren und Komponenten rendern. |
| * Sie können Daten via Props von einer Eltern- an eine Kind-Komponente übergeben. | * Sie können Daten via Props von einer Eltern- an eine Kind-Komponente übergeben. |
| * Sie verstehen, warum lokaler Zustand in der Kind-Komponente sinnvoller ist als ein geteilter State im Parent. | |
| |
| |
| | ''ref()'' | Erstellt eine reaktive Variable | ''const isOpen = ref(false)'' | | | ''ref()'' | Erstellt eine reaktive Variable | ''const isOpen = ref(false)'' | |
| | ''%%{{ }}%%'' | Zeigt einen JS-Wert im Template an | ''%%{{ faqTitle }}%%'' | | | ''%%{{ }}%%'' | Zeigt einen JS-Wert im Template an | ''%%{{ faqTitle }}%%'' | |
| | '':'' (v-bind) | Bindet ein Attribut an einen JS-Wert | '':class="{ open: isOpen }"'' | | | '':'' (v-bind) | Bindet ein HTML-Attribut an einen JS-Wert | '':class="{ open: isOpen }"'' | |
| | ''@'' (v-on) | Reagiert auf ein Event | ''@click="toggleOpen"'' | | | ''@'' (v-on) | Reagiert auf ein Event | ''@click="toggleOpen"'' | |
| </WRAP> | </WRAP> |
| </WRAP> | </WRAP> |
| |
| Vue rendert für jedes Element im Array automatisch ein neues ''%%<div>%%''. Fügen wir dem Array ein neues Objekt hinzu, erscheint sofort ein neues Element im Browser – ohne dass wir das HTML anfassen. | Vue rendert für jedes Element im Array automatisch ein neues ''%%<div>%%''. Fügen wir dem Array ein neues Objekt hinzu, erscheint sofort ein neues Element im Browser. |
| |
| ==== Das key-Attribut ==== | ==== Das key-Attribut ==== |
| |
| <WRAP tip round> | <WRAP tip round> |
| '':key'' braucht einen eindeutigen Wert – idealerweise eine ID aus den Daten. | '':key'' braucht einen eindeutigen Wert – idealerweise eine ID aus den Daten oder der Datenbank. |
| Verwenden Sie nie den Index des Arrays als Key, wenn sich die Reihenfolge ändern kann. | |
| </WRAP> | </WRAP> |
| |
| ===== Das Problem mit einem gemeinsamen State ===== | ===== Das Problem mit einem gemeinsamen State ===== |
| |
| Wenn wir ''v-for'' direkt im Accordion verwenden und ''isOpen'' im Parent lebt, teilen alle Items denselben Zustand – klickt man auf eine Frage, reagieren alle gleichzeitig: | Wenn wir ''v-for'' direkt im Accordion verwenden und ''isOpen'' im Parent gesetzt wird, teilen alle Items denselben Zustand – klickt man auf eine Frage, reagieren alle gleichzeitig: |
| |
| <WRAP box center round 80%> | <WRAP box center round 80%> |
| Eine **Komponente** ist ein abgeschlossener UI-Baustein mit eigenem Template, eigenem Script und eigenem Style. Sie kann beliebig oft verwendet werden. | Eine **Komponente** ist ein abgeschlossener UI-Baustein mit eigenem Template, eigenem Script und eigenem Style. Sie kann beliebig oft verwendet werden. |
| |
| {{:de:modul:m291:learningunits:lu10:theorie:komponenten_eltern_kind.png?direct&700|Eltern-Kind-Beziehung zwischen Accordion und AccordionItem}} | {{:de:modul:m291:learningunits:lu10:theorie:components.png?direct&1100|Eltern-Kind-Beziehung zwischen Accordion und AccordionItem}} |
| |
| In unserem Accordion: | |
| | Jede ''AccordionItem''-Komponente verwaltet ihr ''isOpen'' selbst. |
| | |
| | ===== Props: Daten vom Parent zum Kind ===== |
| | |
| | {{:de:modul:m291:learningunits:lu10:theorie:props_parent-to-child.png?direct&1100| Props von Eltern an Kind-Komponenten übergeben}} |
| | |
| | Mit **Props** können wir Daten von einer Eltern-Komponente an eine Kind-Komponente übergeben. |
| |
| <WRAP box center round 80%> | <WRAP box center round 80%> |
| <code> | <code html> |
| Accordion.vue (Parent) | <template> |
| │ faqItems = [ {...}, {...}, {...} ] | |
| │ → gibt Daten per Props weiter | |
| │ | |
| ├── AccordionItem.vue isOpen = false ← eigener State | |
| ├── AccordionItem.vue isOpen = false ← eigener State | |
| └── AccordionItem.vue isOpen = true ← eigener State (unabhängig) | |
| </code> | |
| </WRAP> | |
| |
| Jede ''AccordionItem''-Komponente verwaltet ihr ''isOpen'' selbst. Die Komponenten wissen nichts voneinander. | <!-- Elternkomponente mit :faq="item" <- das übergibt "item" als Prop --> |
| | <AccordionItem v-for="item in faqData" :faq="item" /> |
| |
| | </template> |
| |
| ===== Props: Daten vom Parent zum Kind ===== | <script setup> |
| |
| **Props** sind der Weg, wie ein Parent Daten an eine Kind-Komponente übergibt. Man kann sich Props wie Parameter einer Funktion vorstellen: | // Kind-Komponente mit Prop |
| | // AccordionItem.vue empfängt: faq: Object (Datentyp) |
| | const props = defineProps({ |
| | faq: Object, |
| | }); |
| |
| <WRAP box center round 80%> | </script> |
| <code javascript> | |
| // Funktion mit Parameter | |
| function greet(name) { | |
| console.log('Hallo ' + name); | |
| } | |
| |
| // Komponente mit Prop | |
| // AccordionItem.vue empfängt: faq | |
| </code> | </code> |
| </WRAP> | </WRAP> |
| |
| '':faq="item"'' bedeutet: Übergib das aktuelle ''item'' als Prop ''faq'' an ''AccordionItem''. | '':faq="item"'' bedeutet: Übergib das aktuelle ''item'' als Prop ''faq'' an ''AccordionItem''. |
| | |
| | === Warum braucht auch :faq einen Doppelpunkt? === |
| | |
| | <WRAP box center round 80%> |
| | <code html> |
| | <!-- Ohne Doppelpunkt: übergibt den Text "item" als String --> |
| | <AccordionItem faq="item" /> |
| | |
| | <!-- Mit Doppelpunkt: übergibt die JavaScript-Variable "item" --> |
| | <AccordionItem :faq="item" /> |
| | </code> |
| | </WRAP> |
| | |
| | Ohne '':'' erhält ''AccordionItem'' buchstäblich den Text ''"item"'' – vier Zeichen, weiter nichts. Mit '':'' wertet Vue den Ausdruck als JavaScript aus und übergibt das tatsächliche Objekt aus der ''v-for''-Schleife. |
| |
| ==== Props im Template verwenden ==== | ==== Props im Template verwenden ==== |
| <WRAP box center round 80%> | <WRAP box center round 80%> |
| ^ Video ^ Inhalt ^ Dauer ^ | ^ Video ^ Inhalt ^ Dauer ^ |
| | [[#|Video 2 – v-bind]] | Attribute dynamisch binden | 3:22 Min. | | | [[https://bzzch-my.sharepoint.com/:v:/g/personal/guido_koch_bzz_ch/IQBNpKK0Qb0WR5dxLs4ZDILDAbi3qj9tlM66LLyfAWXsbu0?nav=eyJyZWZlcnJhbEluZm8iOnsicmVmZXJyYWxBcHAiOiJPbmVEcml2ZUZvckJ1c2luZXNzIiwicmVmZXJyYWxBcHBQbGF0Zm9ybSI6IldlYiIsInJlZmVycmFsTW9kZSI6InZpZXciLCJyZWZlcnJhbFZpZXciOiJNeUZpbGVzTGlua0NvcHkifX0&e=KMu230|Vue Mastery (en mit de Untertitel) – v-bind]] | Attribute dynamisch binden | 3:22 Min. | |
| | [[#|Video 3 – v-on]] | Events und EventListener | 2:42 Min. | | | [[https://bzzch-my.sharepoint.com/:v:/g/personal/guido_koch_bzz_ch/IQDU62KDSK9fS5KJ_JfcWppFAVkv-KLPGe_rt5SbSxJcDg4?nav=eyJyZWZlcnJhbEluZm8iOnsicmVmZXJyYWxBcHAiOiJPbmVEcml2ZUZvckJ1c2luZXNzIiwicmVmZXJyYWxBcHBQbGF0Zm9ybSI6IldlYiIsInJlZmVycmFsTW9kZSI6InZpZXciLCJyZWZlcnJhbFZpZXciOiJNeUZpbGVzTGlua0NvcHkifX0&e=Um3BYj|Vue Mastery (en mit de Untertitel) – v-on]] | Events und EventListener | 2:42 Min. | |
| | [[#|Video 4 – Style & Class Binding]] | Klassen und Styles dynamisch setzen | 4:50 Min. | | | [[https://bzzch-my.sharepoint.com/:v:/g/personal/guido_koch_bzz_ch/IQDizvMGrec_TLgbV-KmUVtHAQj7qx_TYJxINcaZpuSMLeE?nav=eyJyZWZlcnJhbEluZm8iOnsicmVmZXJyYWxBcHAiOiJPbmVEcml2ZUZvckJ1c2luZXNzIiwicmVmZXJyYWxBcHBQbGF0Zm9ybSI6IldlYiIsInJlZmVycmFsTW9kZSI6InZpZXciLCJyZWZlcnJhbFZpZXciOiJNeUZpbGVzTGlua0NvcHkifX0&e=hwU3dA|Vue Mastery (en mit de Untertitel) – Style & Class Binding]] | Klassen und Styles dynamisch setzen | 4:50 Min. | |
| | [[#|Video 1 – create-vue (Scrimba)]] | Projekt anlegen mit create-vue | 3:07 Min. | | | [[https://bzzch-my.sharepoint.com/:v:/g/personal/guido_koch_bzz_ch/IQAQ4UIL-p7gSJSec-ZJe7aEAWLIS4SMpwl-DxoZIlSCf-Q?nav=eyJyZWZlcnJhbEluZm8iOnsicmVmZXJyYWxBcHAiOiJPbmVEcml2ZUZvckJ1c2luZXNzIiwicmVmZXJyYWxBcHBQbGF0Zm9ybSI6IldlYiIsInJlZmVycmFsTW9kZSI6InZpZXciLCJyZWZlcnJhbFZpZXciOiJNeUZpbGVzTGlua0NvcHkifX0&e=CpBfRy|Scrimba – Projekt setup]] | Projekt anlegen mit create-vue | 3:07 Min. | |
| </WRAP> | </WRAP> |
| |