====== LU10 – Komponenten, v-for und Props ======
===== Lernziele =====
* 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 Daten via Props von einer Eltern- an eine Kind-Komponente übergeben.
===== Repetition: Was wir in LU09 gelernt haben =====
==== Video: ref(), Mustache-Syntax und Komponentenstruktur ====
{{:de:modul:m291:learningunits:lu10:theorie:lu10_en_refs_moustache.mp4?1040x585|Video: ref, Mustache und script/template}}
\\
//Aus dem Vue Mastery Crash Course (Englisch, deutsche Untertitel, 2:35 Min.)//
\\
Das Video zeigt, wie eine Vue-Komponente aufgebaut ist, was ''ref()'' macht und wie die Mustache-Syntax ''%%{{ }}%%'' Daten im Template anzeigt.
Eine kurze Übersicht des Gelernten:
^ Konzept ^ Was es macht ^ Beispiel ^
| ''ref()'' | Erstellt eine reaktive Variable | ''const isOpen = ref(false)'' |
| ''%%{{ }}%%'' | Zeigt einen JS-Wert im Template an | ''%%{{ faqTitle }}%%'' |
| '':'' (v-bind) | Bindet ein HTML-Attribut an einen JS-Wert | '':class="{ open: isOpen }"'' |
| ''@'' (v-on) | Reagiert auf ein Event | ''@click="toggleOpen"'' |
===== Von einem Objekt zu einem Array of Objects =====
In LU09 haben wir die Frage und Antwort in einem einzelnen Objekt gespeichert:
// LU09 – ein einzelnes Objekt
const faqData = {
question: 'What is this project?',
answer: "It's a small but mighty mission..."
}
Für ein echtes Accordion mit mehreren Fragen brauchen wir ein **Array von Objekten**:
import { ref } from 'vue';
const faqItems = ref([
{
id: 1,
question: 'What is this project, and how will it help me?',
answer: "It's a small but mighty mission..."
},
{
id: 2,
question: 'Is this free?',
answer: 'Yes. No coins, no secret handshake...'
},
{
id: 3,
question: 'Can I use this project in my portfolio?',
answer: 'Absolutely. Show it off proudly...'
},
])
Jedes Objekt hat drei Eigenschaften: ''id'', ''question'' und ''answer''. Die ''id'' brauchen wir später für das ''key''-Attribut bei ''v-for''.
===== v-for: Dynamisch über ein Array iterieren =====
==== Video: v-for und Arrays ====
{{:de:modul:m291:learningunits:lu10:theorie:lu10_en_array_v-for.mp4?1040x585|Video: v-for und Arrays}}
\\
//Aus dem Vue Mastery Crash Course (Englisch, deutsche Untertitel, 2:52 Min.)//
\\
**Kontext:** Im Video wird ein fiktiver Online-Shop für Socken als Beispiel verwendet.
Das gezeigte Konzept – ''v-for'' über ein Array – funktioniert aber identisch
in unserem FAQ Accordion. Die Parallele:
^ Socks-App ^ Unser Accordion ^
| ''detail in details'' | ''item in faqItems'' |
| ''%%{{ detail }}%%'' | ''%%{{ item.question }}%%'' |
''v-for'' funktioniert wie eine ''forEach''-Schleife in JavaScript – nur direkt im HTML:
// JavaScript forEach
faqItems.forEach(item => {
console.log(item.question);
});
{{ item.question }}
Vue rendert für jedes Element im Array automatisch ein neues ''%%
%%''. Fügen wir dem Array ein neues Objekt hinzu, erscheint sofort ein neues Element im Browser.
==== Das key-Attribut ====
Bei ''v-for'' sollte jedes Element einen eindeutigen Schlüssel erhalten. Das hilft Vue, die Elemente effizient zu verwalten:
{{ item.question }}
'':key'' braucht einen eindeutigen Wert – idealerweise eine ID aus den Daten oder der Datenbank.
===== Das Problem mit einem gemeinsamen State =====
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:
{{ item.answer }}
Die Lösung: Jede Frage-Antwort-Einheit bekommt ihren **eigenen State** – durch eine eigene Komponente.
===== Komponenten: Wiederverwendbare Bausteine =====
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:components.png?direct&1100|Eltern-Kind-Beziehung zwischen Accordion und AccordionItem}}
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.
==== Props empfangen: defineProps() ====
In der Kind-Komponente deklarieren wir, welche Props wir erwarten:
// AccordionItem.vue –
{{ faq.answer }}
==== Accordion.vue ====
FAQs
===== Zusätzliche Videos zur Vertiefung =====
^ Video ^ Inhalt ^ Dauer ^
| [[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. |
| [[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. |
| [[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. |
| [[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. |