HTML5-Tutorium: JavaScript: Hello World Vue 04: Unterschied zwischen den Versionen
Kowa (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
Kowa (Diskussion | Beiträge) |
||
| Zeile 153: | Zeile 153: | ||
=== <code>SectionQuestion.vue</code> === | === <code>SectionQuestion.vue</code> === | ||
<code>SectionQuestion</code> enthält nur noch ein <code>section</code>-Element. Die Buttons und das Textfield werden als Komponenten eingebunden. | |||
<source lang="html"> | |||
// src/components/section/SectionQuestion.vue | |||
<script setup> | |||
import Button from '@/components/form/Button.vue' | |||
import Textfield from '@/components/form/Textfield.vue' | |||
import storeSection from '@/store/StoreSection' | |||
import storeGreeting from '@/store/StoreGreeting' | |||
const | |||
section = storeSection(), | |||
greeting = storeGreeting(), | |||
sayHello = () => { section.change('hello') } | |||
</script> | |||
<template> | |||
<section id="section_question" v-bind:class="section.visability('question')"> | |||
<h1>{{greeting.helloStranger}}</h1> | |||
<form> | |||
<div> | |||
<Textfield label="What's your name?" autofocus | |||
v-model:text="greeting.name" @enter="sayHello" | |||
/> | |||
</div> | |||
<div> | |||
<Button label="Reset" type="reset" /> | |||
<Button label="Say Hello" @click="sayHello"/> | |||
</div> | |||
</form> | |||
</section> | |||
</template> | |||
<style scoped lang="scss"> | |||
@import '@/css/section/SectionQuestion.scss' | |||
</style> | |||
</source> | |||
<source lang="scss"> | |||
// src/css/section/SectionQuestion.scss | |||
@import './_Section.scss' | |||
</source> | |||
<source lang="scss"> | |||
// src/css/section/_Section.scss | |||
@import 'config'; | |||
section | |||
{ text-align: center; | |||
margin-left: auto; | |||
margin-right: auto; | |||
h1 | |||
{ font-size: $font-size-h1; | |||
margin-bottom: 0.5ex; | |||
} | |||
} | |||
</source> | |||
=== <code>SectionHello.vue</code> === | === <code>SectionHello.vue</code> === | ||
<source lang="html"> | |||
// src/components/section/SectionHello.vue | |||
<script setup> | |||
import storeSection from '@/store/StoreSection' | |||
import storeGreeting from '@/store/StoreGreeting' | |||
const | |||
section = storeSection(), | |||
greeting = storeGreeting() | |||
</script> | |||
<template> | |||
<section id="section_hello" v-bind:class="section.visability('hello')"> | |||
<h1>{{greeting.hello}}</h1> | |||
<p>Welcome to Web Programming!</p> | |||
</section> | |||
</template> | |||
<style scoped lang="scss"> | |||
@import '@/css/section/SectionHello.scss' | |||
</style> | |||
</source> | |||
<source lang="scss"> | |||
// src/css/section/SectionHello.scss | |||
@import './_Section.scss' | |||
section | |||
{ p | |||
{ font-size: $font-size-p-large !important; } | |||
} | |||
</source> | |||
== Modularisieren der Hello-World-Komponente == | |||
Nun besteht die Hello-World-Komponenten nur noch aus zwei Section-Komponenten. | |||
Allerdings muss noch die Startkomponente, das heißt die Komponenten, die zunächst sichtbar sein soll, initialisiert werden. | |||
Dies kann später entfallen, wenn die Stores mit Hilfe von JSON-Dateien initialisiert werden. | |||
<source lang="html"> | |||
// src/components/HelloWorld.vue | |||
<script setup> | |||
import SectionQuestion from '@/components/section/SectionQuestion.vue' | |||
import SectionHello from '@/components/section/SectionHello.vue' | |||
import storeSection from '@/store/StoreSection' | |||
const section = storeSection() | |||
section.init({name: 'question'}) | |||
</script> | |||
<template> | |||
<main> | |||
<SectionQuestion/> | |||
<SectionHello/> | |||
</main> | |||
</template> | |||
</source> | |||
Das Folgende ist nur eine Dummy-SCSS-Datei, die aus Symmetriegründen | |||
angelegt wurde: Für jede Komponente gibt es | |||
gemäß WK-Konvention eine eigene SCSS-Datei. | |||
<style scoped lang="scss"> | |||
// src/css/HelloWorld.scss | |||
@import 'config' | |||
</style> | |||
</source> | |||
==Fortsetzung des Tutoriums== | ==Fortsetzung des Tutoriums== | ||
Version vom 18. April 2023, 11:07 Uhr
Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:
| Korrektheit: 3 (zu größeren Teilen überprüft) |
Umfang: 4 (unwichtige Fakten fehlen) |
Quellenangaben: 3 (wichtige Quellen vorhanden) |
Quellenarten: 5 (ausgezeichnet) |
Konformität: 3 (gut) |
Inhalt | Teil 1 | Teil 2 | Teil 3 | Teil 4 | Teil 5 | Teil 6 | Vue 1 | Vue 2 | Vue 3 | Vue 4 | Vue 5 | Vue 6
Musterlösung
Git-Repository, git checkout v04 (JavaScript)
Git-Repository (TypeScript), git checkout v04
Anwendungsfälle (Use Cases)
Gegenüber dem ersten, zweiten und dritten Teil des Vue-Tutoriums ändern sich die die Anwendungsfälle nicht. Die Anwendung leistet also genau dasselbe wie zuvor.
Aufgabe
Aufgabe: Modularisieren Sie HelloWorld.vue
Definieren Sie für die Komponente HelloWorld.vue zwei Subkomponenten:
components/section/SectionHello.vuecomponents/section/SectionQuestion.vue
Zuvor sollten Sie zwei wiederverwendbare Hilfskomponenten definieren:
components/form/Button.vuecomponents/form/Textfield.vue
Erstellen eines neuen Projektzweigs
Erstellen Sie einen neuen Projektzweig (branch) innerhalb von hello_world_vue und fügen Sie das Package uuid hinzu:
git checkout v03 # Wechsle in den Branch v03
git checkout -b v04 # Klone v03 in einen neuen Branch v04
npm i uuid
npm i
Erstellen der Hilfskomponenten
Button.vue
Eine parametrisierbare Button-Komponente.
// src/components/form/Button.vue
<script setup>
defineProps
({ type: { type: String, default: 'button' },
label: { type: String, default: 'Button' }
})
const
emit = defineEmits(['click']),
click = () => emit('click')
</script>
<template>
<input :value="label" :type="type" @click="click"/>
</template>
<style scoped lang="scss">
@import '@/css/form/Button.scss'
</style>
Das zugehörige SCSS-Modul importiert lediglich ein SCSS-Modul für Formulare.
// src/css/form/Button.scss
@import './_Form.scss'
Das Formular-SCSS-Modul definiert Eigenschaften, die sich mehrere Formular-Elemente teilen.
// src/css/form/_Form.scss
@import 'config';
label
{ font-family: $font-family-serif;
font-size: $font-size-p !important;
}
label, input
{ width: 10em;
font-size: 100%;
display: inline-block;
box-sizing: border-box;
margin: 0.5ex;
}
label
{ text-align: right; }
Textfield.vue
Eine parametrisierbare Textfield-Komponente zum Erfassen von Texteingaben.
// src/components/form/Textfield.vue
<script setup>
import { computed, onMounted, onUnmounted } from 'vue'
import { v4 as uuid } from 'uuid'
import ControllerKey from '@/controller/ControllerKey'
const
props = defineProps
({ label: { type: String, default: '' },
text: { type: String, default: '' },
autofocus: { type: Boolean, default: false }
}),
id = uuid(),
emit = defineEmits(['update:text', 'enter']),
text = computed
({ get() { return props.text },
set(p_value) { return emit('update:text', p_value) }
}),
enter = () => emit('enter'),
controllerKey = new ControllerKey('Enter', enter, id)
onMounted (() => controllerKey.add())
onUnmounted(() => controllerKey.remove())
</script>
<template>
<div>
<label :for="id" v-if="label !== ''">{{label}}</label>
<input :id="id" type="text" v-model="text" :autofocus="autofocus" />
</div>
</template>
<style scoped lang="scss">
@import '@/css/form/Textfield.scss'
</style>
Mit Hilfe von "computed" wird für die Property "text" bidirektionales Binding ermöglicht.
Die Getterfunktion liest den Wert aus der Property des Aufrufers. Die Setterfunktion
erzeugt bei jeder Änderung ein passendes Ereignis. Der Name des Ereignisse muss laut Vue-Konvention
'update:<Propertyname>' lauten.
Wie zuvor wird das Formular-SCSS-Modul verwendet.
@import './_Form.scss'
Die in diesem SCSS-Modul enthaltenen Inhalte können, sobald die Modularisierung abgeschlossen ist,
aus der Datei body.scss gelöscht werden.
Erstellen der Hello-World-Section-Komponenten
SectionQuestion.vue
SectionQuestion enthält nur noch ein section-Element. Die Buttons und das Textfield werden als Komponenten eingebunden.
// src/components/section/SectionQuestion.vue
<script setup>
import Button from '@/components/form/Button.vue'
import Textfield from '@/components/form/Textfield.vue'
import storeSection from '@/store/StoreSection'
import storeGreeting from '@/store/StoreGreeting'
const
section = storeSection(),
greeting = storeGreeting(),
sayHello = () => { section.change('hello') }
</script>
<template>
<section id="section_question" v-bind:class="section.visability('question')">
<h1>{{greeting.helloStranger}}</h1>
<form>
<div>
<Textfield label="What's your name?" autofocus
v-model:text="greeting.name" @enter="sayHello"
/>
</div>
<div>
<Button label="Reset" type="reset" />
<Button label="Say Hello" @click="sayHello"/>
</div>
</form>
</section>
</template>
<style scoped lang="scss">
@import '@/css/section/SectionQuestion.scss'
</style>
// src/css/section/SectionQuestion.scss
@import './_Section.scss'
// src/css/section/_Section.scss
@import 'config';
section
{ text-align: center;
margin-left: auto;
margin-right: auto;
h1
{ font-size: $font-size-h1;
margin-bottom: 0.5ex;
}
}
SectionHello.vue
// src/components/section/SectionHello.vue
<script setup>
import storeSection from '@/store/StoreSection'
import storeGreeting from '@/store/StoreGreeting'
const
section = storeSection(),
greeting = storeGreeting()
</script>
<template>
<section id="section_hello" v-bind:class="section.visability('hello')">
<h1>{{greeting.hello}}</h1>
<p>Welcome to Web Programming!</p>
</section>
</template>
<style scoped lang="scss">
@import '@/css/section/SectionHello.scss'
</style>
// src/css/section/SectionHello.scss
@import './_Section.scss'
section
{ p
{ font-size: $font-size-p-large !important; }
}
Modularisieren der Hello-World-Komponente
Nun besteht die Hello-World-Komponenten nur noch aus zwei Section-Komponenten.
Allerdings muss noch die Startkomponente, das heißt die Komponenten, die zunächst sichtbar sein soll, initialisiert werden.
Dies kann später entfallen, wenn die Stores mit Hilfe von JSON-Dateien initialisiert werden.
// src/components/HelloWorld.vue
<script setup>
import SectionQuestion from '@/components/section/SectionQuestion.vue'
import SectionHello from '@/components/section/SectionHello.vue'
import storeSection from '@/store/StoreSection'
const section = storeSection()
section.init({name: 'question'})
</script>
<template>
<main>
<SectionQuestion/>
<SectionHello/>
</main>
</template>
Das Folgende ist nur eine Dummy-SCSS-Datei, die aus Symmetriegründen angelegt wurde: Für jede Komponente gibt es gemäß WK-Konvention eine eigene SCSS-Datei.
<style scoped lang="scss">
// src/css/HelloWorld.scss @import 'config'
</style> </source>
Fortsetzung des Tutoriums
Sie sollten nun Teil 5 des Vue-Tutoriums bearbeiten. In diesem Tutorium werden die Daten extern aus JSON-Dateien geladen, erst statisch, dann dynamisch. Zum Schluss wird die Anwendung internationalisiert.
Quellen
- Kowarschick (MMProg): Wolfgang Kowarschick; Vorlesung „Multimedia-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2018; Quellengüte: 3 (Vorlesung)
