Skip to content

Tudo para WordPress, desenvolvimento web — e não só

⚡ Aprender as bases do Vue 3: de uma pasta vazia a componentes

⚡ Aprender as bases do Vue 3: de uma pasta vazia a componentes

Está a olhar para Vue 3 e vê uma framework de frontend elegante do grupo das três grandes. React, Angular, Vue: parece coisa séria. Depois abre o primeiro tutorial e lá estão à sua espera o vite, o create-vue e ficheiros .vue com transpiladores... Apesar de, na verdade, poder incluir o Vue com uma única linha <script> e começar a escrever código de imediato. Sem bundlers, sem JSX, sem inferno de configuração.

A distância entre «quero experimentar» e «escrevi um componente» é aqui mais curta do que em qualquer outro lado. Mas a maioria dos tutoriais não encurta essa distância; limitam-se a repetir a documentação aos pedaços, sem dar uma visão completa. Vê fragmentos de sintaxe dispersos e não consegue perceber como é que se transformam numa aplicação.

Este guia é exatamente o percurso que nós próprios fizemos com Vue: de uma pasta vazia a componentes com props. Vai escrever e executar cada linha. Nada de magia, apenas código funcional e a compreensão da reatividade, o principal superpoder do Vue.

💡 Visão geral rápida:

  • Construir uma aplicação Vue a partir de uma CDN e montá-la no DOM: a sua primeira instância funcional em 5 minutos
  • Percorrer quatro diretivas essenciais, v-for, v-if, v-on e v-bind: os pilares de qualquer template Vue
  • Analisar computed e methods: quando fazer cache e quando chamar
  • Extrair lógica para componentes e passar dados via props: um passo em direção a uma arquitetura real

Criar uma aplicação Vue

Vamos começar do zero absoluto. Nada de create-vue, vite ou vue-cli, apenas uma pasta com dois ficheiros.

Crie o diretório e os ficheiros no terminal:

1mkdir vue3-intro
2cd vue3-intro
3touch index.html app.js

Ou faça o mesmo através do gestor de ficheiros. Agora abra o index.html e escreva o esqueleto:

1<!DOCTYPE html>
2<html lang="ru">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
7 <title>Vue 3 — first steps</title>
8</head>
9<body>
10 <div id="app"></div>
11 <script src="./app.js"></script>
12</body>
13</html>

Três linhas fundamentais. <script src="https://unpkg.com/vue@3/dist/vue.global.js"> carrega o Vue 3 a partir de uma CDN. Esta é a forma mais rápida de começar: a biblioteca carrega como um ficheiro JavaScript normal, sem necessidade de passo de build. <div id="app"> define o ponto de montagem: o local no DOM onde o Vue vai «viver». A terceira linha importa o app.js, onde vamos definir a lógica.

Agora vamos preencher o app.js:

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3'
5 }
6 }
7})
8
9app.mount('#app')

O método Vue.createApp() cria uma instância da aplicação. Recebe um objeto de opções; aqui declarámos uma propriedade course através da função data(). O Vue torna reativa cada propriedade devolvida por data(): quando um valor muda, o DOM atualiza-se automaticamente. Sem necessidade de manipulação manual da árvore.

Mas a aplicação precisa de ser «ligada» a um elemento na página. É isso que app.mount('#app') faz. Sem esta linha, o Vue não reage a nenhuma alteração: a instância é criada, mas não é iniciada.

Resta apenas exibir a propriedade no HTML. Dentro de <div id="app">, escreva:

1<h1>{{ course }}</h1>

As chavetas duplas {{ }} são interpolação, a forma principal de exibir dados nos templates Vue. Tudo o que está dentro de {{ }} é substituído pelo Vue pelo valor da propriedade correspondente de data().

Primeira aplicação Vue 3 no navegador

Abra o index.html no navegador. A página mostra o texto. A sua primeira aplicação está pronta, e foi você que a escreveu, em vez de a gerar através de uma CLI.

Renderizar listas

Numa aplicação real, quase sempre se trabalha com arrays: produtos, tags, publicações. O Vue fornece a diretiva v-for para isso.

Vamos adicionar um array de tags ao data():

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 tags: ['Vue', 'Frontend', 'JavaScript']
8 }
9 }
10})

E no HTML, uma lista:

1<ul>
2 <li v-for="tag in tags">{{ tag }}</li>
3</ul>

A diretiva v-for itera sobre o array tags e cria o seu próprio <li> para cada elemento. A variável tag dentro do ciclo é o elemento atual. O resultado tem este aspeto:

Lista de etiquetas Vue 3 com a diretiva v-for

Uma nuance importante: ao iterar sobre um array, cada elemento do DOM precisa de uma chave única. O Vue utiliza-a para rastrear a identidade dos nós durante as atualizações, o que acelera a re-renderização e previne erros relacionados com o estado.

1<ul>
2 <li v-for="(tag, index) in tags" :key="index">{{ tag }}</li>
3</ul>

:key é uma abreviatura de v-bind:key, que associa o atributo key ao valor do índice. Se tiver um array de objetos, por exemplo { id: 1, name: 'Vue' }, utilize o id como chave em vez do índice. O índice muda quando a ordem é alterada, enquanto o id é estável, o que o torna mais fiável.

Renderização condicional

Muitas vezes precisa de mostrar ou ocultar um elemento com base numa condição: um botão de compra apenas se o curso estiver disponível. O Vue trata disto com a diretiva v-if.

Vamos adicionar uma flag available ao data():

1data() {
2 return {
3 course: 'Introduction to Vue 3',
4 description: 'Basic guide to Vue 3 for beginners',
5 price: '$19.99',
6 available: true,
7 tags: [
8 { id: 1, name: 'Vue' },
9 { id: 2, name: 'Frontend' },
10 { id: 3, name: 'JavaScript' }
11 ]
12 }
13}

E utilizá-la no markup:

1<p v-if="available">Course available for purchase!</p>
2<p v-else>Unfortunately, the course is currently unavailable.</p>

O v-if avalia a expressão entre aspas. Se for truthy, o primeiro bloco é renderizado; caso contrário, o v-else entra em ação. Experimente executar app.available = false na consola do navegador e veja a página reagir instantaneamente.

Renderização condicional em Vue 3 com v-if

Além de v-if / v-else, existem também o v-else-if para cadeias de condições e o v-show. A diferença é fundamental: o v-if remove completamente o elemento do DOM, enquanto o v-show apenas alterna display: none. Opte por v-if quando a condição muda raramente. Use v-show para alternâncias frequentes, como em separadores, onde o desempenho é relevante.

Gestão de eventos

A diretiva v-on, ou @ para abreviar, escuta eventos do DOM: cliques, input, hover. Quando um evento é disparado, o Vue executa o método ou a expressão especificada.

Vamos adicionar um método purchase às opções da app:

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 available: true,
8 tags: [
9 { id: 1, name: 'Vue' },
10 { id: 2, name: 'Frontend' },
11 { id: 3, name: 'JavaScript' }
12 ]
13 }
14 },
15 methods: {
16 purchase() {
17 console.log('Course purchased!')
18 }
19 }
20})

A secção methods contém funções acessíveis no template e noutros métodos através de this. Agora vamos associar a chamada a um botão:

1<button @click="purchase">Buy</button>
Gerir um clique em Vue 3 com v-on

Para ações simples, pode escrever código diretamente em @click:

1<button @click="available = !available">Toggle availability</button>
Alternar estado de botão em Vue 3

Código inline como este é conveniente para operações curtas, como alternar um sinalizador. Mas mova sempre a lógica complexa para métodos; o template deve permanecer legível. Uma regra simples: counter += 1 é aceitável no template, mas dez linhas de lógica de compra pertencem a um método.

Binding de atributos

Atributos como src, href ou alt precisam frequentemente de ser dinâmicos. A diretiva v-bind, ou : para abreviar, vincula o valor de um atributo a uma expressão Vue.

Vamos adicionar dados para uma imagem:

1data() {
2 return {
3 // ...other properties
4 imgURL: 'https://catalins.tech/img',
5 imgDescription: 'Photo of a desk with a computer'
6 }
7}

No template, vincule-os a um <img>:

1<img :src="imgURL" :alt="imgDescription" width="500" height="350">

A forma completa seria v-bind:src="imgURL"; os dois pontos são apenas açúcar sintático. O Vue agora monitoriza imgURL e imgDescription: altere-os em data() e a imagem na página atualiza-se automaticamente. Isto é a reatividade em ação.

Associar atributos de imagem com v-bind

O mesmo princípio aplica-se a atributos como :href, :disabled e :class, bem como a quaisquer outros. Experimente: adicione um link com um href dinâmico a partir de data() e confirme que funciona sem uma única linha extra.

Propriedades computadas

Por vezes, os dados precisam de ser transformados antes da exibição: formatar um preço, concatenar um nome próprio e apelido, verificar uma condição. O Vue disponibiliza propriedades computed para isso.

Imagine que quer ter sempre uma descrição de imagem, mesmo que o campo imgDescription esteja vazio. Vamos escrever uma propriedade computada:

1const app = Vue.createApp({
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 available: true,
8 imgURL: 'https://catalins.tech/img',
9 imgDescription: 'Photo of a desk with a computer',
10 tags: [
11 { id: 1, name: 'Vue' },
12 { id: 2, name: 'Frontend' },
13 { id: 3, name: 'JavaScript' }
14 ]
15 }
16 },
17 computed: {
18 hasImageDescription() {
19 return this.imgDescription.length > 0
20 ? this.imgDescription
21 : 'Automatic image description'
22 }
23 }
24})

Agora use a propriedade computada no template em vez dos dados brutos:

1<img :src="imgURL" :alt="hasImageDescription" width="500" height="350">

O Vue guarda em cache o resultado de uma propriedade computed e recalcula-a apenas quando as suas dependências mudam, no nosso caso imgDescription. Isto é mais eficiente do que chamar uma função em cada renderização.

Uma regra importante: as propriedades computadas destinam-se a exibir dados, não a alterá-los. Não modifique o estado da aplicação dentro de computed; use métodos para isso.

Métodos vs. propriedades computadas

A diferença entre methods e computed resume-se a uma pergunta: está a alterar dados ou a exibir um valor derivado?

As propriedades computadas são para a camada de apresentação. Formatação, filtragem, verificações de condições, concatenação de strings. São armazenadas em cache e não têm efeitos colaterais.

Os métodos são para ações. Alterar um valor em data(), enviar um pedido, alternar um sinalizador. São chamados explicitamente e podem fazer qualquer coisa.

Um anti-padrão típico é modificar this.course dentro de uma propriedade computed. Uma propriedade computada reage a alterações em course, mas não deve alterá-lo ela própria. Use sempre um método para modificar dados. Deixe o template descrever «o que mostrar», não «como calculá-lo».

Componentes e props

À medida que uma aplicação cresce, manter tudo num único ficheiro torna-se ingerível. O Vue permite dividir a interface em componentes: blocos isolados com a sua própria lógica, template e estilos.

Vamos criar o nosso primeiro componente, CourseCard:

1mkdir components
2touch components/CourseCard.js

Em components/CourseCard.js, defina o componente:

1app.component('coursedisplay', {
2 data() {
3 return {
4 course: 'Introduction to Vue 3',
5 description: 'Basic guide to Vue 3 for beginners',
6 price: '$19.99',
7 available: true,
8 imgURL: 'https://catalins.tech/img',
9 imgDescription: 'Photo of a desk with a computer',
10 tags: [
11 { id: 1, name: 'Vue' },
12 { id: 2, name: 'Frontend' },
13 { id: 3, name: 'JavaScript' }
14 ]
15 }
16 },
17 computed: {
18 hasImageDescription() {
19 return this.imgDescription.length > 0
20 ? this.imgDescription
21 : 'Automatic image description'
22 }
23 },
24 template: `
25 <img :src="imgURL" :alt="hasImageDescription" width="500" height="350">
26 <h1>{{ course }}</h1>
27 <p>{{ description }}</p>
28 <p>{{ price }}</p>
29 <button @click="available = !available">Buy</button>
30 <ul>
31 <li v-for="tag in tags" :key="tag.id">{{ tag.name }}</li>
32 </ul>
33 <p v-if="available">Course available for purchase!</p>
34 <p v-else>Unfortunately, the course is currently unavailable.</p>
35 `
36})

O primeiro argumento de app.component() é o nome que usaremos no HTML como tag: <coursedisplay></coursedisplay>. O segundo é um objeto com data(), computed e template, os «internos» do componente.

Agora vamos incluir o componente em index.html e usá-lo:

1<div id="app">
2 <coursedisplay></coursedisplay>
3</div>
4<script src="./app.js"></script>
5<script src="./components/CourseCard.js"></script>
6<script>
7 const mountedApp = app.mount('#app')
8</script>

Importámos o ficheiro do componente, usámo-lo como uma tag personalizada e montámos a aplicação diretamente no HTML. A lógica do curso está agora encapsulada dentro de CourseCard, enquanto app.js é apenas responsável por criar a instância.

Props: passar dados entre componentes

Props (abreviatura de properties) são o mecanismo para passar dados de um componente pai para um filho. O componente filho declara quais as props que aceita e o pai passa-as como atributos.

Vamos adicionar uma prop paid ao CourseCard que indica se o curso é pago ou gratuito:

1app.component('coursedisplay', {
2 props: {
3 paid: {
4 type: Boolean
5 }
6 },
7 // ...rest of the configuration
8})

O pai, no nosso caso app.js, passa o valor:

1const app = Vue.createApp({
2 data() {
3 return {
4 allCourses: 1,
5 paid: true
6 }
7 }
8})

E em index.html, passamos a prop através de:

1<coursedisplay :paid="paid"></coursedisplay>

O Vue valida automaticamente o tipo do valor passado. Se for esperado um Boolean mas for recebida uma string, a framework emitirá um aviso na consola. Isto poupa-o a erros parvos à medida que a base de código cresce.

Para tornar uma prop obrigatória, adicione required: true à sua definição. O Vue queixar-se-á se o pai não passar um valor, para que saiba do problema antes de ele quebrar a interface.

Pode encontrar o código completo deste guia no repositório vue3-intro no GitHub, que contém os ficheiros finais index.html, app.js e components/CourseCard.js. Faça um fork e experimente.

Vídeo relacionado

Para reforçar a matéria através da prática, veja a primeira lição do curso Vue 3 do Net Ninja; complementa bem este guia com uma demonstração de código ao vivo:

⁉️🤔 Perguntas frequentes

Posso usar Vue 3 sem um bundler em produção?

Sim, incluí-lo via CDN (unpkg.com/vue@3/dist/vue.global.js) também funciona em produção. Mas para projetos reais recomendamos mudar para Vite: obtém tree-shaking, divisão de código e Single-File Components, o que simplifica drasticamente o desenvolvimento à medida que a aplicação cresce. O template inicial npm create vue@latest configura tudo isto num minuto.

Como é que v-if difere de v-show?

v-if remove completamente o elemento do DOM quando a condição é falsa. v-show mantém o elemento no DOM mas alterna a propriedade CSS display: none. Use v-if quando a condição muda raramente, por exemplo, o perfil de utilizador. Use v-show para alternâncias frequentes como separadores, onde a velocidade de renderização importa e quer evitar recriar nós.

A:key é obrigatória no v-for?

Tecnicamente, v-for funciona sem :key, mas o Vue emitirá um aviso na consola. Sem uma key, a framework não consegue rastrear que elemento do DOM corresponde a que elemento de dados, levando a bugs durante reordenações e eliminações. Especifique sempre :key com um identificador único, o id dos seus dados e não o índice do array.

Qual é a diferença entre data() e computed?

data() armazena o estado original, os dados «brutos». computed deriva um valor a partir dele para exibição: uma string formatada, um array filtrado, um resultado de validação. Uma propriedade computed atualiza-se automaticamente quando as suas dependências mudam e é armazenada em cache entre renderizações. Os métodos, por outro lado, são chamados de novo a cada vez e destinam-se a ações, não a exibição.

Posso misturar Options API e Composition API?

Sim, pode usar ambos os estilos num único projeto. O Vue 3 suporta totalmente a Options API, enquanto a Composition API é uma ferramenta adicional para cenários complexos. Para aprendizagem, recomendamos começar com a Options API: é mais estruturada e mais próxima do modelo mental de «um componente é um objeto com opções».

O que fazer a seguir: o seu próximo passo com Vue 3

Construiu a sua primeira aplicação, explorou diretivas, propriedades computed e componentes. Esta é a base sobre a qual qualquer projeto é construído, desde uma landing page a um painel de administração.

Há três caminhos a seguir. Primeiro, solidifique através da prática: agarre numa API pública como JSONPlaceholder e exiba uma lista de publicações com filtragem via computed. Segundo, passe para Vite e ficheiros .vue: a documentação oficial do Vue 3 guiá-lo-á do create-vue ao seu primeiro SFC numa hora. Terceiro, aprenda Vue Router e Pinia para construir uma SPA completa.

Se quiser experimentar o Vue sem qualquer instalação, consulte o artigo sobre como incluir o Vue via CDN. E o código inicial deste guia está no repositório vue3-intro; faça um fork e experimente.