SVELTE, Creando componentes
Creando componentes en Svelte
Como ocurre con otros frameworks, Svelte también nos permite crear nuestros propios componentes consiguiendo de esta forma reutilizar nuestro código.
Antes de comenzar a crear nuestro componente es importante entender cual es el ciclo de vida de un componente en Svelte.
El ciclo de vida de un componente
Se puede definir como los diferentes estados por los que pasa o puede pasar un componente.
En Svelte tenemos los siguientes métodos:
- Creación
- onMount(): Sucede cuando se monta el componente.
- onDestroy(): Sucede cuando se destruye el componente.
- Actualización
- beforeUpdate(): Sucede antes de actualizar el DOM.
- afterUpdate(): Sucede después de actualizar el DOM.
- tick(): Sucede cuando todos los métodos del ciclo de vida estén finalizados. (Este método debe ir dentro de un método del ciclo de vida).
A continuación un pequeño ejemplo:
import { createEventDispatcher, beforeUpdate, adterUpdate, onMount, onDestroy, tick } from 'svelte'; // Ciclo de vida console.log('1 - Ejecución de script'); onMount(async () => { console.log('2 - Mounted'); }); beforeUpdate(async () => { await tick(); console.log('3 - Before Update'); }); afterUpdate(async () => { await tick(); console.log('4 - After Update'); }); onDestroy(() => { console.log('5 - Destroy'); });
En la consola podemos ver el ciclo de vida de un componente en Svelte.
Empecemos con nuestro componente
Para definir un componente se usa la siguiente estructura dentro del fichero:
<script></script> <template></template> <style></style>
Debemos tener en cuenta, que en ningún caso los tres tags (<script>, <style> y <template>) son imprescindible ni dependientes unos de otros en el mismo fichero.
Una vez creado nuestro código, lo guardaremos con la extensión .svelte, y ya tendríamos nuestro componente creado.
Para quien haya usado Vuejs esta sintaxis le resultara muy conocida y fácil de asimilar, ya que Vuejs trabaja de la misma forma, un único archivo con la extensión .vue y los tres tags (<script>, <style> y <template>).
Como ocurre con Vuejs, en Svelte cada fichero .svelte puede ser un pequeño componente sencillo, uno más complejo, una página o una aplicación.
Ahora que sabemos como es la estructura básica de un componente en Svelte, empecemos a crear nuestro primer componente.
Aunque no es obligatorio, si que es recomendable crear una carpeta donde iremos guardando todos nuestros componentes y para nuestro ejemplo la llamaremos components.
Empezaremos con el clásico botón, así que crearemos un fichero llamado button.svelte.
button.svelte
<script> </script> <a href="." class="btn">button</a> <style> .btn { text-decoration: none; color: #fff; background-color: #26a69a; text-align: center; letter-spacing: .5px; transition: background-color .2s ease-out; cursor: pointer; font-size: 14px; outline: 0; border: none; border-radius: 2px; display: inline-block; height: 36px; line-height: 36px; padding: 0 16px; text-transform: uppercase; vertical-align: middle; -webkit-tap-highlight-color: transparent; margin: 10px; } </style>
El componente es muy sencillo y no tiene de momento nada de código Javascript.
Ahora veremos como integrarlo y el resultado.
App.svelte
<script> import PsButton from './components/button.svelte'; </script> <div class="card"> <h1>COMPONENTES</h1> <div class="components"> <PsButton /> </div> </div>
Ahora que sabemos como crear un componente en Svelte, vamos a evolucionar el componente un poco mediante el uso las propiedades.
Añadiendo propiedades a nuestro componente
Para añadir propiedades a nuestro componente usaremos la palabra reservada export seguido de la definición de nuestra propiedad.
// Definición de una propiedad en el componente export let type; // Definición de una propiedad con un valor por defecto en el componente export let type = 'default';
Con esta pequeña sentencia ya tendríamos las propiedades definidas y listas para usar.
button.svelte
<script> export let text = ''; export let type = 'default'; export let disabled = false; $: isDisbled = disabled ? 'disable' : ''; </script> <button class="btn {type} {isDisbled}">{text}</button> <style> .btn { text-decoration: none; color: #fff; text-align: center; letter-spacing: .5px; transition: background-color .2s ease-out; cursor: pointer; font-size: 14px; outline: 0; border: none; border-radius: 2px; display: inline-block; height: 36px; line-height: 36px; padding: 0 16px; text-transform: uppercase; vertical-align: middle; -webkit-tap-highlight-color: transparent; margin: 10px; } .default { background-color: #26a69a; } .error { background-color: #e43d3d; } .warning { background-color: #c3bd43; } .info { background-color: #2599e4; } .disable { pointer-events: none; opacity: .4; } </style>
De nuevo veremos como integrar el componente pero ahora con las propiedades que hemos definido.
button.svelte
<script> import PsButton from './components/button.svelte'; </script> <div class="card"> <h1>COMPONENTES</h1> <div class="components"> <PsButton text="Click" /> <PsButton text="Click" type="error" /> <PsButton text="Click" type="warning" /> <PsButton text="Click" type="info" /> <PsButton text="Click" type="default" /> <PsButton text="Click" type="error" disabled={true} /> </div> </div>
Como hemos podido comprobar, tanto la definición de las propiedades como su uso han resultado ser bastante simples.
Ya tenemos nuestro componente creado y gracias a las propiedades podemos personalizarlo, realizando la comunicación desde fuera (padre) hacia dentro (hijo).
Pero…, ¿que ocurre si queremos comunicarnos desde dentro (hijo) hacia fuera (padre)?.
Bien, para realizar esta tarea debemos importar un método que es el encargado de emitir nuestro eventos personalizados (custom events).
Eventos para comunicarnos con el exterior
Importando el método createEventDispatcher ya podríamos emitir desde nuestro componente hacia fuera cualquier dato.
button.svelte
<script> import { createEventDispatcher } from 'svelte'; export let text = ''; export let type = 'default'; export let disabled = false; $: isDisbled = disabled ? 'disable' : ''; const dispatch = createEventDispatcher(); const clickFn = () => { dispatch('click-evt', { msn: 'inside' }); }; </script> <button class="btn {type} {isDisbled}" on:click={clickFn}>{text}</button>
App.svelte
<script> const clickMethod = evt => { // Dentro del objeto evt, llega el valor detail con el payload console.log(evt, evt.detail); }; import PsButton from './components/button.svelte'; </script> <PsButton text="Evento" type="default" on:click-evt={clickMethod} />
Podemos ver que en el componente hemos creado un evento llamado click-evt y en el componente de nuestra página mediante on: hemos vinculado ese evento.
Como habíamos dicho al principio, en ese evento podemos emitir un valor (payload) que lo recibiríamos fuera.
Bien, ya hemos visto como podemos comunicarnos desde fuera hacia dentro mediante las propiedades, y desde dentro hacia fuera mediante los eventos.
Existe otra forma de comunicación desde fuera hacia dentro de un componente, y es mediante el uso de slots.
Usando slots en Svelte
Que bien un Slot, pero…. ¿que es un Slot?
Un Slot lo podemos definir como una zona dentro del componente donde podemos añadir nuestro propio contenido desde fuera del componente.
A continuación un pequeño ejemplo.
button.svelte
<script> import { createEventDispatcher } from 'svelte'; export let text = ''; export let type = 'default'; export let disabled = false; $: isDisbled = disabled ? 'disable' : ''; const dispatch = createEventDispatcher(); const clickFn = () => { dispatch('click-evt', { msn: 'inside'}); }; </script> <button class="btn {type} {isDisbled}" on:click={clickFn}> <slot>{text}</slot> <slot name="info-text">Texto defecto</slot> </button>
App.svelte
<PsButton> <span class="btn-special">Slot botón 0</span> </PsButton> <PsButton> <span class="btn-special">Slot botón 1</span> <span slot="info-text" class="btn-special">Texto info</span> </PsButton>
Con el ejemplo anterior podemos comprobar que el uso de Slots en nuestros componentes puede ser una características bastante potente que nos permite personalizar y ampliar el propio componente.
Para finalizar, añadiré el código del componente y el repositorio a Github.
Button.svelte
<script> import { createEventDispatcher, beforeUpdate, afterUpdate, onMount, onDestroy, tick } from 'svelte'; export let text = ''; export let type = 'default'; export let disabled = false; $: isDisbled = disabled ? 'disable' : ''; const dispatch = createEventDispatcher(); const clickFn = () => { dispatch('click-evt', { msn: 'inside'}); }; // Ciclo de vida console.log('1 - Ejecución de script'); onMount(async () => { console.log('2 - Mounted'); }); beforeUpdate(async () => { await tick(); console.log('3 - Before Update'); }); afterUpdate(async () => { await tick(); console.log('4 - After Update'); }); onDestroy(() => { console.log('5 - Destroy'); }); let status = false; const enter = () => { status = true; }; const exit = () => { status = false; }; </script> <button class="btn {type} {isDisbled}" on:click={clickFn} on:mouseenter={enter} on:mouseleave={exit}> <slot status={status}>{text}</slot> <slot name="info-text">Texto defecto</slot> </button> <style> .btn { text-decoration: none; color: #fff; text-align: center; letter-spacing: .5px; transition: background-color .2s ease-out; cursor: pointer; font-size: 14px; outline: 0; border: none; border-radius: 2px; display: inline-block; height: 36px; line-height: 36px; padding: 0 16px; text-transform: uppercase; vertical-align: middle; -webkit-tap-highlight-color: transparent; margin: 10px; } .default { background-color: #26a69a; } .error { background-color: #e43d3d; } .warning { background-color: #c3bd43; } .info { background-color: #2599e4; } .disable { pointer-events: none; opacity: .4; } </style>
Un comentario en «SVELTE, Creando componentes»