En plus des attributs, les éléments peuvent avoir des directives, qui contrôlent le comportement des éléments de différentes manières.
on:eventnamepermalink
on:eventname={handler}
on:eventname|modifiers={handler}
Utilisez la directive on:
pour écouter des évènements du DOM.
<script>
let count = 0;
function handleClick(event) {
count += 1;
}
</script>
<button on:click={handleClick}>
Compte: {count}
</button>
Les gestionnaires d'évènement peuvent être déclarés directement sans pénaliser les performances. Comme pour les attributs, les valeurs utilisées pour les directives peuvent être mises entre guillemets afin d'aider la coloration syntaxique.
<button on:click="{() => count += 1}">
Compte: {count}
</button>
Ajoutez des modificateurs aux évènements DOM avec le caractère |
.
<form on:submit|preventDefault={handleSubmit}>
<!-- le comportement par défaut de l'évènement `submit` est ignoré,
ce qui permet de ne pas recharger la page -->
</form>
Les modificateurs suivants sont disponibles:
preventDefault
— appelleevent.preventDefault()
avant d'exécuter le gestionnaire d'évènementstopPropagation
— appelleevent.stopPropagation()
, empêchant l'évènement d'atteindre le prochain élémentstopImmediatePropagation
- appelleevent.stopImmediatePropagation()
, empêchant d'autres gestionnaires du même évènement d'être exécutéspassive
— améliore la performance du défilement pour les évènementstouch
/wheel
(Svelte l'ajoutera automatiquement lorsque qu'il détecte que ce n'est pas problématique)nonpassive
— déclare explicitement l'évènement avecpassive: false
capture
— déclenche le gestionnaire d'évènement pendant la phase de capture plutôt que pendant la phase de bubblingonce
— supprime le gestionnaire d'évènement après sa première exécutionself
— ne déclenche le gestionnaire d'évènement que sievent.target
est l'élément lui-mêmetrusted
— ne déclenche le gestionnaire d'évènement que sievent.isTrusted
esttrue
. C'est-à-dire si l'évènement est déclenché par une action utilisateur.
Vous pouvez chaîner les modificateurs, par ex. on:click|once|capture={...}
.
Si la directive on:
est utilisée sans valeur, le composant relaiera l'évènement à son parent, ce qui permettra à ce dernier de l'écouter.
<button on:click>
Le composant lui-même va émettre un évènement clic
</button>
Il est possible d'avoir plusieurs gestionnaires pour le même évènement:
<script>
let counter = 0;
function increment() {
counter = counter + 1;
}
function track(event) {
trackEvent(event)
}
</script>
<button on:click={increment} on:click={track}>Cliquez moi !</button>
bind:propertypermalink
bind:property={variable}
En général, la donnée descend du parent vers l'enfant. La directive bind:
permet à la donnée de remonter de l'enfant vers le parent. Le plus souvent ces liaisons sont spécifiques à des éléments particuliers.
L'exemple le plus simple d'une liaison reflète la valeur d'une propriété, comme input.value
.
<input bind:value={name}>
<textarea bind:value={text}></textarea>
<input type="checkbox" bind:checked={yes}>
Si le nom de la variable est le même que le nom de la propriété, vous pouvez simplifier l'écriture.
<!-- Ces écritures sont équivalentes -->
<input bind:value={value}>
<input bind:value>
Les valeurs numériques sont traitées comme des nombres ; même si input.value
est une chaîne de caractères pour le DOM, Svelte traitera cette valeur comme un nombre. Si l'<input>
est vide ou invalide (dans le cas de type="number"
par exemple), la valeur sera undefined
.
<input type="number" bind:value={num}>
<input type="range" bind:value={num}>
Sur les éléments <input>
de type type="file"
, vous pouvez utiliser bind:files
pour obtenir la FileList
des fichiers sélectionnés. Cette liste est en lecture seule.
<label for="avatar">Choisissez une image :</label>
<input
accept="image/png, image/jpeg"
bind:files
id="avatar"
name="avatar"
type="file"
/>
Si vous utilisez des directives bind:
conjointement à des directives on:
, l'ordre dans lequel elles sont définies affectera la valeur de la variable liée lorsque la fonction d'écoute sera appelée.
<script>
let value = 'Bonjour tout le monde';
</script>
<input
on:input={() => console.log('Ancienne valeur:', value)}
bind:value
on:input={() => console.log('Nouvelle valeur:', value)}
/>
Dans ce cas, nous avons lié la valeur d'un <input>
de texte qui utilise l'évènement input
. Des liaisons sur d'autres éléments pourraient utiliser d'autres évènements comme change
.
Lier les valeurs de <select>permalink
Une liaison sur un <select>
correspond à la propriété value
de l'<option>
sélectionnée, qui peut être n'importe quelle valeur (pas uniquement des chaînes de caractères, comme c'est le cas en général dans le DOM).
<select bind:value={selected}>
<option value={a}>a</option>
<option value={b}>b</option>
<option value={c}>c</option>
</select>
Un élément <select multiple>
se comporte de manière similaire à un groupe de <checkbox>
. La variable liée est un tableau avec un élément correspondant à la propriété value
de chaque <option>
sélectionnée.
<select multiple bind:value={fillings}>
<option value="Riz">Riz</option>
<option value="Haricots">Haricots</option>
<option value="Fromage">Fromage</option>
<option value="Guacamole (supplément)">Guacamole (supplément)</option>
</select>
Quand la valeur d'une <option>
correspond à son contenu texte, l'attribut peut être ignoré.
<select multiple bind:value={fillings}>
<option>Riz</option>
<option>Haricots</option>
<option>Formage</option>
<option>Guacamole (supplément)</option>
</select>
Les éléments avec l'attribut contenteditable
permettent les liaisons suivantes:
Il y a de légères différences entre ces différentes liaisons, apprenez-en plus ici.
<div contenteditable="true" bind:innerHTML={html}></div>
Les éléments <details>
permettent les liaisons avec la propriété open
.
<details bind:open={isOpen}>
<summary>Détails</summary>
<p>
Quelque chose suffisamment petit pour passer inaperçu.
</p>
</details>
Liaisons d'éléments mediapermalink
Les éléments media (<audio>
et <video>
) ont leurs propres liaisons — au nombre de 7 et en lecture seule ...
duration
(lecture seule) — durée totale de la vidéo, en secondesbuffered
(lecture seule) — tableau d'objets{start, end}
played
(lecture seule) — idemseekable
(lecture seule) — idemseeking
(lecture seule) — booléenended
(lecture seule) — booléenreadyState
(lecture seule) — nombre entre 0 (inclus) et 4 (inclus)
... et 5 liaisons lecture-écriture :
currentTime
— temps actuel de lecture de la vidéo, en secondesplaybackRate
— vitesse de lecture de la vidéo, 1 étant 'normal'paused
— a priori vous voyez ce que c'estvolume
— une valeur entre 0 et 1muted
— booléen indiquant si le lecteur est en sourdine
Les vidéos ont de plus des liaisons en lecture seule pour les attributs videoWidth
et videoHeight
.
<video
src={clip}
bind:duration
bind:buffered
bind:played
bind:seekable
bind:seeking
bind:ended
bind:readyState
bind:currentTime
bind:playbackRate
bind:paused
bind:volume
bind:muted
bind:videoWidth
bind:videoHeight
></video>
Liaisons des éléments imagepermalink
Les éléments d'image (<img>
) ont deux liaisons en lecture seule :
naturalWidth
(lecture seule) — la largeur d'origine de l'image, disponible après le chargement de l'imagenaturalHeight
(lecture seule) — la hauteur d'origine de l'image, disponible après le chargement de l'image
<img
bind:naturalWidth
bind:naturalHeight
></img>
Liaisons des éléments de type blockpermalink
Les éléments de type block
ont 4 liaisons en lecture seule, mesurées en utilisant une technique similaire à celle-ci (en anglais):
clientWidth
clientHeight
offsetWidth
offsetHeight
<div
bind:offsetWidth={width}
bind:offsetHeight={height}
>
<Chart {width} {height}/>
</div>
bind:grouppermalink
bind:group={variable}
Les inputs qui fonctionnent ensemble peuvent utiliser bind:group
.
<script>
let tortilla = 'Simple';
let fillings = [];
</script>
<!-- les inputs radio groupés sont mutuellement exclusifs -->
<input type="radio" bind:group={tortilla} value="Simple">
<input type="radio" bind:group={tortilla} value="Complète">
<input type="radio" bind:group={tortilla} value="Épinards">
<!-- les inputs checkbox groupés remplissent un tableau -->
<input type="checkbox" bind:group={fillings} value="Riz">
<input type="checkbox" bind:group={fillings} value="Haricots">
<input type="checkbox" bind:group={fillings} value="Fromage">
<input type="checkbox" bind:group={fillings} value="Guacamole (supplément)">
bind:group
ne fonctionne que si les<input>
sont dans le même composant Svelte.
bind:thispermalink
bind:this={dom_node}
Utiliser bind:this
vous permet d'obtenir une référence à un noeud DOM.
<script>
import { onMount } from 'svelte';
let canvasElement;
onMount(() => {
const ctx = canvasElement.getContext('2d');
drawStuff(ctx);
});
</script>
<canvas bind:this={canvasElement}></canvas>
class:namepermalink
class:name={value}
class:name
Une directive class:
permet de facilement ajouter ou enlever une classe à un élément.
<!-- Ces syntaxes sont équivalentes -->
<div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div>
<!-- Syntaxe raccourcie, quand le nom de la variable correspond au nom de la classe -->
<div class:active>...</div>
<!-- Plusieurs directives `class:` peuvent être utilisées -->
<div class:active class:inactive={!active} class:isAdmin>...</div>
style:propertypermalink
style:property={value}
style:property="value"
style:property
La directive style:
fournit un raccourci pour modifier directement le style d'un élément.
<!-- Ces syntaxes sont équivalentes -->
<div style:color="red">...</div>
<div style="color: red;">...</div>
<!-- Vous pouvez utiliser des variables -->
<div style:color={myColor}>...</div>
<!-- Syntaxe raccourcie, quand le nom de la variable correspond au nom de la propriété -->
<div style:color>...</div>
<!-- Plusieurs directives `style:` peuvent être utilisées -->
<div style:color style:width="12rem" style:background-color={darkMode ? "black" : "white"}>...</div>
<!-- Vous pouvez définir des styles comme importants -->
<div style:color|important="red">...</div>
Quand des directives style:
sont combinées avec des attributs style
, les directives sont prioritaires.
<div style="color: blue;" style:color="red">Ceci sera rouge</div>
use:actionpermalink
use:action
use:action={parameters}
ts
action = (node :HTMLElement ,parameters : any) => {update ?: ( parameters : any) => void,destroy ?: () => void }
Les actions sont des fonctions exécutées lorsqu'un élément est créé. Elles peuvent renvoyer un objet avec une méthode destroy
qui sera appelée lors de la destruction de l'élément.
<script>
function foo(node) {
// le noeud a été ajouté au DOM
return {
destroy() {
// le noeud a été supprimé du DOM
}
};
}
</script>
<div use:foo></div>
Une action peut avoir un argument. Si la valeur renvoyée possède une méthode update
, celle-ci sera exécutée à chaque fois que cet argument changera, juste après que Svelte a appliqué les modifications au markup.
Ne vous inquiétez pas du fait que l'on redéclare la fonction
foo
pour chaque instance — Svelte garde en mémoire toute fonction qui ne dépend pas d'un état local en dehors de la définition du composant.
<script>
export let bar;
function foo(node, bar) {
// le noeud a été ajouté au DOM
return {
update(bar) {
// la valeur de `bar` a changé
},
destroy() {
// le noeud a été supprimé du DOM
}
};
}
</script>
<div use:foo={bar}></div>
Plus d'infos dans la page svelte/action
.
transition:fnpermalink
transition:fn
transition:fn={params}
transition:fn|global
transition:fn|global={params}
transition:fn|local
transition:fn|local={params}
ts
transition = (node :HTMLElement ,params : any,options : {direction : 'in' | 'out' | 'both' }) => {delay ?: number ,duration ?: number ,easing ?: ( t : number) =>number ,css ?: ( t : number,u : number) =>string ,tick ?: ( t : number,u : number) => void}
Une transition est déclenchée lorsqu'un élément entre ou sort du DOM après un changement d'état.
Quand un bloc transitionne vers sa sortie, tous les éléments au sein du bloc, y compris ceux n'ayant pas de transition propre, sont laissés dans le DOM tant que toutes les transitions du bloc se soient terminées.
La directive transition:
établit une transition bidirectionnelle, ce qui implique qu'elle peut être inversée sans heurts en cours de transition.
{#if visible}
<div transition:fade>
s'estompe en entrant et en sortant
</div>
{/if}
Les transitions sont locales par défaut (dans Svelte 3, elles étaient globales par défaut). Les transitions locales sont jouées uniquement lorsque le bloc auquel elles appartiennent est créé ou détruit, pas lorsqu'un bloc parent est créé ou détruit.
{#if x}
{#if y}
<!-- Svelte 3: <p transition:fade|local> -->
<p transition:fade>entre et sort en s'estompant seulement quand y change</p>
<!-- Svelte 3: <p transition:fade> -->
<p transition:fade|global>entre et sort en s'estompant quand x ou y change</p>
{/if}
{/if}
Par défaut, les transitions d'entrée (
in
) ne sont pas jouées au premier rendu. Vous pouvez modifier ce comportement en appliquantintro: true
lorsque vous instanciez manuellement un composant.
Paramètres de transitionpermalink
À l'instar des actions, les transitions peuvent avoir des paramètres.
(La syntaxe {{accolades}}
n'est pas spéciale ; il s'agit simplement d'un objet dans une balise d'expression.)
{#if visible}
<div transition:fade="{{ duration: 2000 }}">
s'estompe en entrant et en sortant sur une durée de 2 secondes
</div>
{/if}
Transitions personnaliséespermalink
Les transitions peuvent être définies par des fonctions personnalisées. Si l'objet retourné possède une fonction css
, Svelte créera une animation CSS qui sera jouée sur l'élément.
L'argument t
passé à css
est une valeur entre 0
et 1
après que la fonction easing
a été appliquée. Les transitions entrantes sont jouées de 0
à 1
, les transitions sortantes sont jouées de 1
à 0
— en d'autres termes, 1
est l'état normal de l'élément, comme si aucune transition ne lui était appliquée. L'argument u
est égal à 1 - t
.
La fonction est régulièrement appelée avant que la transition ne commence, avec différentes valeurs pour t
et u
.
<script>
import { elasticOut } from 'svelte/easing';
/** @type {boolean} */
export let visible;
/**
* @param {HTMLElement} node
* @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params
*/
function whoosh(node, params) {
const existingTransform = getComputedStyle(node).transform.replace('none', '');
return {
delay: params.delay || 0,
duration: params.duration || 400,
easing: params.easing || elasticOut,
css: (t, u) => `transform: ${existingTransform} scale(${t})`
};
}
</script>
{#if visible}
<div in:whoosh>entre en faisant woosh</div>
{/if}
Une fonction de transition personnalisée peut aussi renvoyer une fonction tick
, qui est appelée pendant la transition avec les mêmes arguments t
et u
.
Il est recommandé d'utiliser
css
plutôt quetick
, si possible — les animations CSS sont exécutées sur un thread différent de celui de JS, évitant ainsi de ralentir les machines les moins puissantes.
<script>
export let visible = false;
/**
* @param {HTMLElement} node
* @param {{ speed?: number }} params
*/
function typewriter(node, { speed = 1 }) {
const valid = (
node.childNodes.length === 1 &&
node.childNodes[0].nodeType === Node.TEXT_NODE
);
if (!valid) {
throw new Error(`Cette transition ne fonctionne que sur les éléments avec un seul noeud texte comme enfant`);
}
const text = node.textContent;
const duration = text.length / (speed * 0.01);
return {
duration,
tick: t => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
}
};
}
</script>
{#if visible}
<p in:typewriter="{{ speed: 1 }}">
Portez ce vieux whisky au juge blond qui fume
</p>
{/if}
<script lang="ts">
export let visible = false;
function typewriter(node: HTMLElement, { speed = 1 }: { speed?: number }) {
const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE;
if (!valid) {
throw new Error(
`Cette transition ne fonctionne que sur les éléments avec un seul noeud texte comme enfant`,
);
}
const text = node.textContent;
const duration = text.length / (speed * 0.01);
return {
duration,
tick: (t) => {
const i = ~~(text.length * t);
node.textContent = text.slice(0, i);
},
};
}
</script>
{#if visible}
<p in:typewriter="{{ speed: 1 }}">
Portez ce vieux whisky au juge blond qui fume
</p>
{/if}
Si une transition retourne une fonction au lieu d'un objet transition, la fonction sera appelée lors de la prochaine micro-tâche. Cela permet à plusieurs transitions de se coordonner, rendant les effets de fondu croisé possibles.
Les fonctions de transition peuvent aussi avoir un troisième argument, options
, qui contient des informations sur la transition.
Les valeurs possibles dans l'objet options
sont:
direction
-in
,out
, orboth
, selon le type de transition
Évènements de transitionpermalink
Un élément ayant des transitions génére les évènements suivants en plus des évènements DOM standards:
introstart
introend
outrostart
outroend
{#if visible}
<p
transition:fly="{{ y: 200, duration: 2000 }}"
on:introstart="{() => status = "début de l'entrée"}"
on:outrostart="{() => status = "début de la sortie"}"
on:introend="{() => status = "fin de l'entrée"}"
on:outroend="{() => status = "fin de la sortie"}"
>
Entre et sort en volant
</p>
{/if}
in:fn/out:fnpermalink
in:fn
in:fn={params}
in:fn|global
in:fn|global={params}
in:fn|local
in:fn|local={params}
out:fn
out:fn={params}
out:fn|global
out:fn|global={params}
out:fn|local
out:fn|local={params}
Similaire à transition:
, mais s'applique uniquement aux éléments entrant (in:
) ou sortant (out:
) du DOM.
Contrairement à transition:
, les transitions appliquées avec in:
et out:
ne sont pas bi-directionnelles — une transition entrante continuera sa course en parallèle de la transition sortante, plutôt que d'être inversée, si le bloc est supprimé pendant la transition en cours. Si une transition sortante est annulée, les transitions seront rejouées du début.
{#if visible}
<div in:fly out:fade>
entre en volant, sort en fondu
</div>
{/if}
animate:fnpermalink
animate:name
animate:name={params}
ts
animation = (node :HTMLElement , {from :DOMRect ,to :DOMRect } ,params : any) => {delay ?: number ,duration ?: number ,easing ?: ( t : number) =>number ,css ?: ( t : number,u : number) =>string ,tick ?: ( t : number,u : number) => void}
ts
DOMRect {bottom:number ,height :number ,left :number ,right :number ,top :number ,width :number ,x :number ,y :number }
Une animation est déclenchée quand le contenu d'un bloc each
à clé est réordonné. Les animations ne sont pas jouées lorsqu'un élément est ajouté ou supprimé, seulement lorsque l'indice d'un élément de liste change au sein d'un bloc each
. Les directives animate:
doivent appartenir à un élément enfant direct d'un bloc each
à clé.
Les animations peuvent être utilisées avec les fonctions d'animation natives de Svelte ou avec des fonctions d'animation personnalisées.
<!-- Quand `list` est réordonnée, l'animation sera jouée -->
{#each list as item, index (item)}
<li animate:flip>{item}</li>
{/each}
Paramètres d'animationpermalink
À l'instar des actions et des transitions, les animations peuvent avoir des paramètres.
(La syntaxe {{accolades}}
n'est pas spéciale; il s'agit simplement d'un objet dans une balise d'expression.)
{#each list as item, index (item)}
<li animate:flip="{{ delay: 500 }}">{item}</li>
{/each}
Fonctions d'animation personnaliséespermalink
Les animations peuvent être définies par des fonctions fournissant un node
, un objet animation
, et n'importe quels parameters
en arguments. L'argument animation
est un objet ayant les propriétés from
et to
, chacune contenant un DOMRect décrivant la géométrie de l'élément dans ses positions de départ (start
) et arrivée (end
). La propriété from
est le DOMRect de l'élément dans sa position de départ, la propriété to
est le DOMRect de l'élément dans sa position d'arrivée après que la liste a été réordonnée et le DOM mis à jour.
Si l'objet renvoyé a une méthode css
, Svelte va créer une animation CSS qui sera jouée sur l'élément.
L'argument t
passé à css
est une valeur qui va de 0
à 1
avec que la fonction easing
a été appliquée. L'argument u
est égal à 1 - t
.
La fonction est régulièrement appelée avant que la transition ne commence, avec différentes valeurs pour t
et u
.
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t*360}deg);`
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}
Une fonction d'animation personnalisée peut aussi renvoyer une fonction tick
, qui est appelée pendant la transition avec les mêmes arguments t
et u
.
Il est recommandé d'utiliser
css
plutôt quetick
, si possible — les animations CSS sont exécutées sur un thread différent de celui de JS, évitant ainsi de ralentir les machines les moins puissantes.
<script>
import { cubicOut } from 'svelte/easing';
/**
* @param {HTMLElement} node
* @param {{ from: DOMRect; to: DOMRect }} states
* @param {any} params
*/
function whizz(node, { from, to }, params) {
const dx = from.left - to.left;
const dy = from.top - to.top;
const d = Math.sqrt(dx * dx + dy * dy);
return {
delay: 0,
duration: Math.sqrt(d) * 120,
easing: cubicOut,
tick: (t, u) =>
Object.assign(node.style, { color: t > 0.5 ? 'Pink' : 'Blue' })
};
}
</script>
{#each list as item, index (item)}
<div animate:whizz>{item}</div>
{/each}