Cours Svelte et SvelteKit · Module 10: Actions
Modèles d'actions populaires
Dans cette leçon5
Chargement différé d'images
export function lazyLoad(node, src) {
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
node.src = src;
observer.disconnect();
}
});
observer.observe(node);
return {
destroy() {
observer.disconnect();
}
};
}<img use:lazyLoad={'/images/viking.jpg'} alt="Viking" />Focus automatique
export function autoFocus(node) {
node.focus();
}<input use:autoFocus placeholder="Focus automatique !" />Portail
export function portal(node, target = 'body') {
const targetEl = document.querySelector(target);
targetEl.appendChild(node);
return {
destroy() {
node.remove();
}
};
}<div use:portal={'#modals'}>
Contenu de la fenêtre modale
</div>Appui long
export function longpress(node, duration = 500) {
let timer;
function handleMouseDown() {
timer = setTimeout(() => {
node.dispatchEvent(new CustomEvent('longpress'));
}, duration);
}
function handleMouseUp() {
clearTimeout(timer);
}
node.addEventListener('mousedown', handleMouseDown);
node.addEventListener('mouseup', handleMouseUp);
node.addEventListener('mouseleave', handleMouseUp);
return {
update(newDuration) {
duration = newDuration;
},
destroy() {
clearTimeout(timer);
node.removeEventListener('mousedown', handleMouseDown);
node.removeEventListener('mouseup', handleMouseUp);
node.removeEventListener('mouseleave', handleMouseUp);
}
};
}<button use:longpress={1000} onlongpress={() => alert('Appui long !')}>
Maintiens-moi 1 seconde
</button>En Svelte 5, tu gères un événement personnalisé envoyé par une action avec dispatchEvent grâce à un attribut ordinaire : on + le nom de l'événement, donc onlongpress.
Actions TypeScript
import type { Action } from 'svelte/action';
interface TooltipParams {
text: string;
position?: 'top' | 'bottom';
}
export const tooltip: Action<HTMLElement, TooltipParams> = (node, params) => {
// ... implémentation
return {
update(newParams: TooltipParams) {
// ...
},
destroy() {
// ...
}
};
};
// Le troisième paramètre de type décrit les événements personnalisés de l'action
export const longpress: Action<HTMLElement, number, {
onlongpress: (e: CustomEvent) => void;
}> = (node, duration = 500) => {
// ...
};Code de cette leçon : App.svelte
<script>
// Actions pratiques - resize observer, intersection observer
let width = $state(0);
let height = $state(0);
let visible = $state(false);
// Action resize observer
function resizeObserver(node, callback) {
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
callback(entry.contentRect);
}
});
observer.observe(node);
return {
destroy() {
observer.disconnect();
}
};
}
// Action intersection observer
function inview(node, callback) {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
callback(entry.isIntersecting);
});
}, { threshold: 0.5 });
observer.observe(node);
return {
destroy() {
observer.disconnect();
}
};
}
function handleResize(rect) {
width = Math.round(rect.width);
height = Math.round(rect.height);
}
function handleInview(isVisible) {
visible = isVisible;
}
</script>
<main class="observer-demo">
<h1>Actions Observer</h1>
<section
class="resizable"
use:resizeObserver={handleResize}
>
<h2>ResizeObserver</h2>
<p>Largeur : <strong>{width}px</strong></p>
<p>Hauteur : <strong>{height}px</strong></p>
<p class="hint">Redimensionne la fenêtre du navigateur</p>
</section>
<div class="spacer">
<p>↓ Défile vers le bas ↓</p>
</div>
<section
class="observed"
class:visible
use:inview={handleInview}
>
<h2>IntersectionObserver</h2>
<p>Statut : <strong>{visible ? 'Visible !' : 'Masqué'}</strong></p>
</section>
</main>
<style>
.observer-demo {
font-family: 'Georgia', serif;
max-width: 500px;
margin: 0 auto;
padding: 2rem;
background: #1a1a2e;
color: #e8e8f7;
}
h1 {
color: #7cb3f0;
text-align: center;
}
section {
background: rgba(124, 179, 240, 0.1);
border: 1px solid #7cb3f0;
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}
h2 {
color: #7cb3f0;
font-size: 1rem;
margin-top: 0;
}
strong {
color: #ffd700;
}
.hint {
font-size: 0.85rem;
color: #6a8ab9;
}
.spacer {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #6a8ab9;
}
.observed {
transition: all 0.3s;
opacity: 0.5;
transform: scale(0.95);
}
.observed.visible {
opacity: 1;
transform: scale(1);
border-color: #ffd700;
}
</style>Entrées de la documentation utilisées dans cette leçon
Tu as repéré une erreur dans cette leçon ?
Tâches pratiques dans le jeu
- Éditeur de code
Complète l'action qui donne automatiquement le focus à l'élément