Web-Apps mit Svelte
Ein praktischer Einstieg
Der Trainer
- Nils Röhrig
- Software Engineer @ Loql
- Frontend-Fokus
- Svelte-Nutzer seit 2019
- Speaker auf Konferenzen und Meetups
Agenda
Teil II
- Verschachtelung
- Props
- Komponenten- Slots
- Event Dispatching
- Event Forwarding
- Events oder Callbacks
Teil I
- Framework
- Lokaler State
- Direktiven
- Kontrollstrukturen
- CSS Support
- SVG Support
- Reaktivität
Teil III
- Svelte Stores
- Custom Stores
- Svelte Kontext
- Stores im Kontext
Teil IV
- Arbeit mit Promises
- Transitionen
- Svelte Actions
- DOM-Referenzen
Mittagspause
12:30 - 13:30
Kaffeepausen
15:00 - 15:15 & 16:15 - 16:30
Teil I
Teil I
- Framework
- Lokaler State
- Direktiven
- Kontrollstrukturen
- CSS Support
- SVG Support
- Reaktivität
Svelte ist ein Komponenten-Framework
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Komponente
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Komponente
Komponente
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Komponente
Komponente
etc. pp...
Svelte ist ein Compiler
Svelte ist ein Compiler
<h1>Simple Component</h1>
Component.svelte
Svelte ist ein Compiler
<h1>Simple Component</h1>
Svelte ist ein Compiler
<h1>Simple Component</h1>
Svelte ist ein Compiler
<h1>Simple Component</h1>
import { SvelteComponent, detach, element, init,
insert, noop, safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
let h1;
return {
c() {
h1 = element("h1");
h1.textContent = "Simple Component";
},
m(target, anchor) {
insert(target, h1, anchor);
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(h1);
},
};
}
class SimpleComponent extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, {});
}
}
export default SimpleComponent;
Svelte ist ein Compiler
<h1>Simple Component</h1>
import { [...] } from "svelte/internal";
function create_fragment(ctx) {
let h1;
return {
c() {
h1 = element("h1");
h1.textContent = "Simple Component";
},
m(target, anchor) {
insert(target, h1, anchor);
},
p: noop, i: noop, o: noop,
d(detaching) { if (detaching) detach(h1); },
};
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment,
safe_not_equal, {});
}
}
export default Component;
Component.js
Svelte ist ein Compiler
<h1>Simple Component</h1>
import Component from "./Component.js";
const app = new Component({
target: document.body,
});
export default app;
main.js
Dateistruktur
Dateistruktur
<script>
// STATE & BEHAVIOR
</script>
<!-- DECLARATIVE MARKUP -->
<h1>Hello enterJS!</h1>
<p>{"Put your JS expressions in curly braces."}</p>
<style>
/* PRESENTATION */
</style>
Component.svelte
Lokaler State
Lokaler State
- Der lokale Komponenten-State in Svelte besteht aus lokalen Variablen.
- Er beschreibt den Zustand der Komponente und ist nicht mit anderen Komponenten geteilt.
- Der lokale State ist reaktiv im Svelte-Sinne, d.h. bei Änderungen werden nur die betroffenen Teile der Komponente aktualisiert.
Direktiven
Direktiven
- Svelte-Direktiven sind als Attribute in Svelte-Elementen verwendbar.
- Sie können das Verhalten von Elementen steuern, z.B. durch das Binden von Daten oder das Behandeln von Ereignissen.
- Svelte bietet verschiedene Direktiven an, die das Verhalten von Elementen steuern können, wie z.B.
on:
undbind:
.
Kontrollstrukturen
Kontrollstrukturen
- Kontrollstrukturen sind ein integraler Bestandteil des Svelte-Markups.
- Sie regeln den Programmfluss und sind aus anderen Programmiersprachen bekannt.
- Svelte bietet eine Block-Syntax für Kontrollstrukturen, die verschiedene Ausdrücke wie
if
,else
,each
, und andere unterstützt.
Veränderung des Wertes eines {#each}
-Blocks
- Wenn der Wert eines
{#each}
-Blocks in Svelte geändert wird, werden nur am Ende des Blocks Elemente entfernt oder hinzugefügt.
- Geänderte Elemente werden an derselben Stelle im DOM aktualisiert.
- Verwendung von eindeutigen IDs kann unerwünschte Effekte vermeiden, wenn gerenderte Elemente nicht direkt oder reaktiv von der Änderung des Werts abhängig sind.
Keyed Each Block
Lokale Konstanten
Reaktivität
Reaktivität
- Svelte integriert Reaktivität als Kernelement.
- Der
=
-Operator und seine Varianten werden in Svelte verwendet, um Datenbindung zwischen Variablen und UI-Elementen herzustellen.
- Svelte verfolgt Abhängigkeiten zwischen Variablen und aktualisiert nur die Teile des DOM, die davon betroffen sind.
- Durch Build-Time-Tracking der Zuweisungen wird der Code optimiert.
- Svelte bietet Sprachunterstützung wie Reactive Statements.
CSS Support
CSS Support
- CSS ist Teil des Single-File-Component-Ansatzes in Svelte.
- Styles sind automatisch scopiert, um Konflikte zu vermeiden.
- Direktiven ermöglichen das Binding von Klassen.
- Es gibt auch Direktiven zum gezielten Setzen einzelner CSS-Properties.
SVG Support
SVG Support
- Svelte bietet vollständigen Support für SVG-Grafiken.
- SVG-Elemente können direkt in Svelte-Komponenten eingebunden werden.
- Svelte ermöglicht das dynamische Aktualisieren von SVG-Attributen und -Eigenschaften.
Live Coding
Übung
Übung
- Füge Filter für Transaktionen hinzu:
- All time: Alle Transaktionen
- Monthly: Aktueller Monat
- Weekly: Aktuelle Kalenderwoche
- Die Filterung sollte sich widerspiegeln in
- den StatCards
- der Transaktionstabelle
Hinweise
- Die Art der Implementierung ist frei wählbar
- Module in src/lib können verwendet werden
Aufgaben
git checkout tags/part_1_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
Repository
Lösungsvorschlag
Teil II
Teil II
- Verschachtelung
- Props
- Komponenten- Slots
- Event Dispatching
- Event Forwarding
- Events oder Callbacks
Verschachtelung von Komponenten
Verschachtelung von Komponenten
E-Mail
Submit
Register
Home
Logo
Verschachtelung von Komponenten
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
E-Mail
Submit
Register
Home
Logo
<Logo>
<Header>
<App>
<NavItem>
<NavItem>
<NavBar>
<Label>
<Input>
<Form>
<Button>
Komponenten-Slots
Komponenten-Slots
- Slots in Svelte ermöglichen die dynamische Injektion von Inhalten in Komponenten.
- Sie werden mithilfe des
<slot>
-Elements in Komponenten definiert.
- Slotinhalte werden durch Elternkomponenten bereitgestellt
- Slotinhalte können beliebiges gültiges Svelte-Markup enthalten.
Komponenten-Slots
Dialog
Text der im Dialog angezeigt wird. Potenziell ergänzt um weiteren Content.
Okay
Komponenten-Slots
<strong>Dialog</strong>
<p>Text der im Dialog angezeigt wird. Potenziell ergänzt um weiteren Content.</p>
<button>Okay</button>
Props
Props
Register
Home
Props
<NavItem>
<NavItem>
Register
Home
Props
<NavItem >
<NavItem >
label="Home"
label="Register"
Register
Home
Props
<script>
const str = "a string";
const num = 12345;
const bool = true;
const obj = {key: "value"};
const arr = [1, 2, 3, 4, 5];
function callback() {
console.log("callback");
}
</script>
<AnyComponent
stringProp={str}
numberProp={num}
booleanProp={bool}
objectProp={obj}
arrayProp={arr}
{callback}
/>
Props
<script>
const str = "a string";
const num = 12345;
const bool = true;
const obj = {key: "value"};
const arr = [1, 2, 3, 4, 5];
function callback() {
console.log("callback");
}
</script>
<AnyComponent
stringProp={str}
numberProp={num}
booleanProp={bool}
objectProp={obj}
arrayProp={arr}
{callback}
/>
<script>
export let stringProp = "";
export let numberProp = 0;
export let booleanProp = true;
export let objectProp = {key: "value"};
export let arrayProp = [1, 2, 3];
export let callback = () => undefined;
</script>
<p>{stringProp}</p>
<p>{numberProp}</p>
<p>{booleanProp}</p>
{#each Object.entries(objectProp) as [key, value]}
<p>{key}: {value}</p>
{/each}
{#each arrayProp as value}
<p>{value}</p>
{/each}
<button on:click={callback}>Call back</button>
$$props & $$restProps
Event-Dispatching
Event-Dispatching
E-Mail
Submit
Register
Home
Logo
Event-Dispatching
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
<App>
<Form>
Event-Dispatching
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
<App>
<Form>
Wie?
Event-Dispatching
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("form:posted", { /* any information to share */ });
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
Event-Dispatching
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("form:posted", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:form:posted={handleSubmit} />
App.svelte
Event-Forwarding
Event-Forwarding
- Event-Forwarding leitet Ereignisse von Kindkomponenten an übergeordnete Komponenten weiter.
- Dadurch können Elternkomponenten auf Benutzeraktionen in ihren Kindkomponenten reagieren.
- Es fördert die Koordination von Daten und Aktionen über die Komponentenhierarchie hinweg.
Event-Forwarding
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
<form on:submit>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
async function handleSubmit(event) {
const data = new FormData(event.target);
await postData(data);
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Events vs. Callbacks
Events vs. Callbacks
<script>
import AnotherComponent from './AnotherComponent.svelte';
function callback() {
console.log("I am a callback. Arguments: ", ...arguments);
}
</script>
<AnotherComponent {callback} />
<script>
export let callback;
</script>
<button on:click={callback}>
Click me!
</button>
Component.svelte
AnotherComponent.svelte
Events vs. Callbacks
<script>
import Button from './Button.svelte';
function handleButtonElementClick() {
console.log("Button element clicked.");
}
function handleButtonComponentClick() {
console.log("Button component clicked.");
}
</script>
<button on:click={handleButtonElementClick}>Button element</button>
<Button onClick={handleButtonComponentClick}>Button Component</Button>
Live Coding
Übung
Übung
- Erstelle eine Detailseite für Transaktionen
- Die Detailseite sollte alle Informationen zu einer Transaktion enthalten
- Auf jeder Detailseite kann die jeweilige Transaktion gelöscht werden
Hinweise
- Die Art der Implementierung ist frei wählbar
- Die Beispiel-App nutzt modifizierte StatCards
Aufgaben
git checkout tags/part_2_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
Repository
Lösungsvorschlag
Teil III
Teil III
- Svelte Stores
- Custom Stores
- Svelte Context
- Stores im Kontext
Svelte Stores
Svelte Stores
- Stores sind JavaScript-Objekte, die Werte kapseln und über eine
.subscribe
-Methode abonniert werden können.
- Abonnenten werden über Aktualisierungen benachrichtigt.
- Svelte bietet Sprachunterstützung für die Verwendung von Stores.
- Es gibt verschiedene Arten von mitgeliferten Stores, namentlich
readable
,writable
undderived
.
Svelte Store Contract
- Ein Store muss eine
.subscribe
-Methode enthalten, die als Argument eine Subscription-Funktion akzeptiert, um ein Abo zu erstellen.
- Die Subscription-Funktion muss sofort und synchron mit dem aktuellen Wert des Stores aufgerufen werden, wenn
.subscribe
aufgerufen wird.
- Alle aktiven Subscription-Funktionen des Stores müssen später synchron aufgerufen werden, wenn sich der Wert des Stores ändert.
-
.subscribe
muss eine Unsubscribe-Funktion zurückgeben. Deren Aufruf muss das Abo beenden und die entsprechende Subscription-Funktion darf nicht erneut vom Store aufgerufen werden.
- Ein Store kann optional eine
.set
-Methode enthalten, welche als Argument einen neuen Wert akzeptiert und den Store damit aktualisiert. Ein solcher Store wird als Writable Store bezeichnet.
Custom Stores
Svelte Kontext
Svelte Kontext
- Der Kontext ist ein Key-Value-Store, der eine Datenübertragung von einer Komponente zu allen ihr hierarchisch untergeordneten Komponenten ohne explizite Props ermöglicht.
-
setContext()
wird verwendet, um den Kontext in der übergeordneten Komponente zu erstellen und bereitzustellen.
-
getContext()
wird verwendet, um den Kontext in den untergeordneten Komponenten abzurufen.
- Der Kontext kann beliebige Werte enthalten, wie z.B. Konfigurationsdaten, Funktionen oder Stores.
- Der Kontext ist nicht reaktiv im Svelte-Sinne.
Stores im Kontext
Live Coding
Übung
Übung
- Erstelle eine Mechanik zur Synchronisierung der Transaktionen in den Local Storage des Browsers
Hinweise
- Die Art der Implementierung ist frei wählbar
- Stores können abonniert werden
https://slides.com/nilsroehrig/svelte-workshop-enterjs-2023
Aufgaben
git checkout tags/part_3_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
Repository
Lösungsvorschlag
Teil IV
Teil IV
- Arbeit mit Promises
- Transitionen
- Refs & Actions
Arbeit mit Promises
Arbeit mit Promises
Komponente Rendern
Daten Abrufen
Anzeige Aktualisieren
Arbeit mit Promises
Komponente Rendern
Daten Abrufen
Anzeige Aktualisieren
Transitionen
Transitionen
- Transitionen in Svelte ermöglichen animierte Übergänge beim Hinzufügen oder Entfernen von DOM-Elementen.
- Sie werden über die
transition
-Direktive verwendet und ermöglichen die Nutzung eingebauter oder benutzerdefinierter Transitionen.
- Svelte beinhaltet bereits Transitionseffekte wie
fade
,slide
oderscale
.
- Benutzerdefinierte Funktionseffekte folgen einer einheitlichen Schnittstelle, die in der Svelte-Dokumentation zu finden ist.
Transitionen
Refs & Actions
Refs & Actions
- Refs sind eine Möglichkeit zum referenzieren von DOM-Elementen.
- Sie werden über die
bind:this={variable}
-Direktive erstellt und können wie andere Variablen verwendet und geteilt werden.
- Actions sind Funktionen die direkt an DOM-Elementen geknüpft werden können, ohne eine explizite Referenz zu erstellen.
- Sie werden über die
use:actionName={params}
-Direktive verwendet.
- Actions werden beim Hinzufügen zum DOM ausgeführt.
- Sie können optional eine Funktion zurückgeben, die beim Entfernen aus dem DOM ausgeführt wird.
Live Coding
Übung
Übung
- Erstelle eine Visualisierung für Einnahmen und Ausgaben mit Chart.js
Hinweise
- Chart.js ist bereits in den Abhängigkeiten gelistet
- Nutze Svelte Actions um Visualisierungen ins DOM zu bringen
- Diagrammtyp, Art der Implementierung, usw. sind darüber hinaus frei wählbar
Aufgaben
git checkout tags/part_4_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
Repository
Blitzlicht
- Was - wenn überhaupt - hab ich heute gelernt?
- Was - wenn überhaupt - hat mir besonders gut gefallen?
- Was - wenn überhaupt - würde ich mir beim nächsten Mal anders wünschen?
Web-Apps mit Svelte (enterJS 2023)
By Nils Röhrig
Web-Apps mit Svelte (enterJS 2023)
- 1,216