Skip to main content

Sintaxe

Componentes da Svelte

Editar esta página na GitHub

Os componentes são blocos de construção de aplicações de Svelte. Eles são escritos dentro dos ficheiros .svelte, usando um superconjunto de HTML.

Todas as três seções — <script> (o programa), <style> (o estilo), e a marcação — são opcionais.

<script>
  // a lógica
</script>

<!-- marcação (zero ou mais itens) -->

<style>
  /* estilos */
</style>

<script>

Um bloco <script> contém JavaScript que executa-se quando uma instância de componente é criada. As variáveis declaradas (ou importadas) no alto nível estão 'visíveis' a partir da marcação do componente. Existem quatro regras adicionais:

1. export cria uma propriedade de componente

A Svelte usa a palavra-chave export para marcar uma declaração de variável como uma propriedade, o que significa que torna-se acessível aos consumidores do componente (consulte a seção sobre atributos e propriedades por mais informações):

<script>
  export let foo;

  // Os valores que são passados como propriedades
  // estão imediatamente disponíveis
  console.log({ foo });
</script>

Nós podemos especificar um valor inicial padrão para uma propriedade. Ele será usado se o consumidor do componente não especificar a propriedade no componente (ou se seu valor inicial for undefined) quando inicializarmos o componente. Nota que se os valores das propriedades forem subsequentemente atualizados, então qualquer propriedade cujo valor não for especificado será definida para undefined (no lugar do seu valor inicial).

No modo de desenvolvimento (consulte as opções do compilador), um aviso será imprimido se nenhum valor inicial padrão for fornecido e o consumidor não especificar um valor. Para reprimir este aviso, garantimos que um valor inicial padrão é especificado, mesmo se for undefined:

<script>
  export let bar = 'optional default initial value';
  export let baz = undefined;
</script>

Se exportarmos uma const, class ou function, está disponível apenas para leitura a partir de fora do componente. As funções são valores de propriedade válidos, no entanto, como mostrado abaixo:

App.svelte
<script>
  // estas são apenas para leitura
  export const thisIs = 'readonly';

  /** @param {string} name */
  export function greet(name) {
    alert(`hello ${name}!`);
  }

  // isto é uma propriedade
  export let format = (n) => n.toFixed(2);
</script>
App.svelte
<script lang="ts">
  // estas são apenas para leitura
  export const thisIs = 'readonly';
  
  export function greet(name: string) {
    alert(`hello ${name}!`);
  }
  
  // isto é uma propriedade
  export let format = (n) => n.toFixed(2);
</script>

As propriedades exclusivas para leitura podem ser acessadas como propriedades no elemento, atados ao componente usando a sintaxe bind:this.

Nós podemos usar palavras reservadas como nomes de propriedade:

App.svelte
<script>
  /** @type {string} */
  let className;

  // cria uma propriedade `class`, apesar
  // de ser uma palavra reservada
  export { className as class };
</script>
App.svelte
<script lang="ts">
  let className: string;
  
  // cria uma propriedade `class`, apesar
  // de ser uma palavra reservada
  export { className as class };
</script>

2. Atribuições são 'reativas'

Para mudar o estado do componente e acionar um redesenho, apenas precisamos atribuir à uma variável declarada localmente.

As atualizações de expressão (count += 1) e atribuições de propriedade (obj.x = y) têm o mesmo efeito:

<script>
  let count = 0;

  function handleClick() {
    // a chamada desta função acionará uma
    // atualização se a marcação referir-se à `count`
    count = count + 1;
  }
</script>

Uma vez que a reatividade da Svelte está baseada nas atribuições, o uso de métodos de vetor como .push() e .splice() não acionará automaticamente as atualizações. Uma atribuição subsequente é necessária para acionar a atualização. Este e mais detalhes podem ser encontrados no tutorial:

<script>
  let arr = [0, 1];

  function handleClick() {
    // esta chamada de método não aciona uma atualização
    arr.push(2);
    // esta atribuição acionará uma atualização
    // se a marcação referir-se à `arr`
    arr = arr;
  }
</script>

Os blocos de <script> da Svelte são executados apenas quando o componente for criado, assim as atribuições dentro dum bloco de <script> não são automaticamente executadas novamente quando uma propriedade atualizar-se. Se gostaríamos de rastrear mudanças à uma propriedade, o próximo exemplo na seguinte seção mostra-nos como fazê-lo:

<script>
  export let person;
  // isto apenas definirá `name` na criação do componente
  // não atualizar-se-á quando `person` atualizar-se
  let { name } = person;
</script>

3. $: marca uma declaração como reativa

Qualquer declaração de alto nível (por exemplo, que não estiver dentro dum bloco ou duma função) pode ser tornada reativa prefixando-a com a $: sintaxe de rótulo da JavaScript. As declarações reativas executam depois do outro código do programa e antes do componente ser desenhado, sempre que os valores que de que dependem tiver sido mudado.

<script>
  export let title;
  export let person;

  // isto atualizará `document.title` sempre
  // que a propriedade `title` mudar
  $: document.title = title;

  $: {
    console.log(`multiple statements can be combined`);
    console.log(`the current title is ${title}`);
  }

  // isto atualizará `name` quando `person´ mudar
  $: ({ name } = person);

  // não fazer isto. executará antes da linha anterior
  let name2 = name;
</script>

Apenas os valores que aparecem diretamente dentro do bloco $: tornar-se-ão dependências da declaração reativa. Por exemplo, no código baixo total apenas atualizar-se-á quando x mudar, mas não y:

App.svelte
<script>
  let x = 0;
  let y = 0;

  /** @param {number} value */
  function yPlusAValue(value) {
    return value + y;
  }

  $: total = yPlusAValue(x);
</script>

Total: {total}
<button on:click={() => x++}> Increment X </button>

<button on:click={() => y++}> Increment Y </button>
App.svelte
<script lang="ts">
  let x = 0;
  let y = 0;
  
  function yPlusAValue(value: number) {
    return value + y;
  }
  
  $: total = yPlusAValue(x);
</script>

Total: {total}
<button on:click={() => x++}> Increment X </button>

<button on:click={() => y++}> Increment Y </button>

É importante notar que os blocos reativos são ordenados através duma simples analise estática em tempo de compilação, e tudo que o compilador vê são as variáveis que são atribuídas à e usadas dentro do próprio bloco, não em quaisquer funções chamadas por elas. Isto significa que yDependent não será atualizado quando x for atualizada no seguinte exemplo:

<script>
  let x = 0;
  let y = 0;

  /** @param {number} value */
  function setY(value) {
    y = value;
  }

  $: yDependent = y;
  $: setY(x);
</script>

O ato de mover a linha $: yDependent = y por baixo de $: setY(x) fará a yDependent ser atualizada quando x for atualizada.

Se uma declaração consistir inteiramente duma atribuição à uma variável não declarada, a Svelte injetará uma declaração let em nosso nome:

App.svelte
<script>
  /** @type {number} */
  export let num;

  // não precisamos de declarar `squared` e `cubed`
  // — a Svelte faz isto por nós
  $: squared = num * num;
  $: cubed = squared * num;
</script>
App.svelte
<script lang="ts">
  export let num: number;
  
  // não precisamos de declarar `squared` e `cubed`
  // — a Svelte faz isto por nós
  $: squared = num * num;
  $: cubed = squared * num;
</script>

4. Prefixar as memórias com $ para acessar os seus valores

Uma memória é um objeto que permite o acesso reativo à um valor através dum simples contrato de memória. O módulo svelte/store contém implementações de memória minimalista que satisfaz este contrato.

Em qualquer momento que tivermos uma referência à uma memória, podemos acessar o seu valor dentro dum componente prefixando-a com o carácter $. Isto faz a Svelte declarar a variável prefixada, subscrever à memória na inicialização do componente e anular a subscrição quando apropriado.

As atribuições às variáveis prefixadas pelo $ exigem que a variável seja uma memória gravável, e resultará numa chamada ao método .set da memória.

Nota que a memória deve ser declarada no alto nível do componente — não dentro dum bloco if ou duma função, por exemplo.

As variáveis locais (que não representam os valores da memória) não devem ter um prefixo $:

<script>
  import { writable } from 'svelte/store';

  const count = writable(0);
  console.log($count); // logs 0

  count.set(1);
  console.log($count); // logs 1

  $count = 2;
  console.log($count); // logs 2
</script>

Contrato de Memória

ts
store = { subscribe: (subscription: (value: any) => void) => (() => void), set?: (value: any) => void }

Nós podemos criar as nossas próprias memórias sem depender da svelte/store, ao implementar o contrato de memória:

  1. Uma memória deve conter um método .subscribe, o qual deve aceitar como seu argumento uma função de subscrição. Esta função de subscrição deve ser chamada imediatamente e de maneira síncrona com o valor atual da memória ao chamar .subscribe. Todas as funções de subscrição ativas duma memória devem ser posteriormente chamadas de maneira síncrona sempre que o valor da memória mudar.
  2. O método .subscribe deve retornar uma função de anulação de subscrição. A chamada duma função de anulação de subscrição deve parar a sua subscrição, e a sua função de subscrição correspondente não deve ser chamada novamente pela memória.
  3. Uma memória pode opcionalmente conter um método .set, o qual deve aceitar como seu argumento um novo valor para a memória, e que chama de maneira síncrona todas as funções de subscrição ativas da memória. Tal memória é chamada de memória gravável.

Para interoperabilidade com os observáveis de RxJS, o método .subscribe também está permitido retornar um objeto com um método .unsubscribe, ao invés de retornar a função de anulação de subscrição diretamente. Nota, no entanto, que a menos que .subscribe chame de maneira síncrona a subscrição (o que não é exigido pela especificação do Observável), a Svelte verá o valor da memória como undefined até que isto aconteça.

<script context="module">

Um marcador <script> com um atributo context="module" é executado uma vez quando o módulo é avaliado pela primeira vez, e nãp para cada instância do componente. Os valores declarados neste bloco são acessíveis a partir dum <script> normal (e a marcação do componente), mas não vice-versa.

Nós podemos fazer export de vínculos a partir deste bloco, e tornar-se-ão exportações do módulo compilado.

Nós não podemos fazer export default, visto que a exportação padrão é o próprio componente.

As variáveis definidas nos programas de module não são reativas — reatribuí-las não acionará uma nova interpretação, mesmo que a própria variável seja atualizada. Para os valores partilhados entre vários componentes devemos considerar usar uma memória.

<script context="module">
  let totalComponents = 0;

  // a palavra-chave `export` permite esta função ser importada com
  //  por exemplo `import Example, { alertTotal } from './Example.svelte'`
  export function alertTotal() {
    alert(totalComponents);
  }
</script>

<script>
  totalComponents += 1;
  console.log(`total number of times this component has been created: ${totalComponents}`);
</script>

<style>

A CSS dentro dum bloco <style> será isolada para este componente.

Isto funciona adicionando uma classe aos elementos afetados, que é baseada numa sequência de caracteres embaralhados dos estilos do componente (por exemplo, svelte-123xyz):

<style>
  p {
    /* isto apenas afetará os elementos <p> neste componente */
    color: burlywood;
  }
</style>

Para aplicar estilos à um seletor globalmente, usamos o modificador :global(...):

<style>
  :global(body) {
    /* isto aplicar-se-á ao <body> */
    margin: 0;
  }

  div :global(strong) {
    /* isto aplicar-se-á à todos elementos <strong>, dentro de
       qualquer componente, que estão dentro de elementos <div>
       que pertencem à este componente */
    color: goldenrod;
  }

  p:global(.red) {
    /* isto aplicar-se-á à todos elementos <p> que pertencem à
       este componente com a classe `red`, mesmo se `class="red"`
       não aparecer inicialmente na marcação, e é ao invés disto
       adicionada em tempo execução. Isto é útil quando a classe
       do elemento é aplicada dinamicamente, por exemplo quando
       atualizamos a propriedade `classList` do elemento diretamente. */
  }
</style>

Se quisermos criar @keyframes que são acessíveis globalmente, precisamos de prefixar os nomes dos quadros-chave com -global-.

A parte -global- será removida quando compilada, e o quadro-chave então será referenciado usando apenas my-animation-name em algum lugar no nosso código:

<style>
  @keyframes -global-my-animation-name {
    /* o código é escrito neste bloco */
  }
</style>

Deveria apenas existir 1 marcador <style> de alto nível por componente.

No entanto, é possível ter um marcador <style> encaixado dentro doutros elementos ou blocos lógicos.

Neste caso, o marcador <style> será inserido tal como está no DOM, nenhum isolamento ou processamento será feito sobre o marcador <style>:

<div>
  <style>
    /* este marcador de estilo será inserido como está */
    div {
      /* isto aplicar-se-á à todos elementos `<div>` no DOM */
      color: red;
    }
  </style>
</div>
anterior Introdução