Vue.js Tutorial: Iniciando com componentes

Késsia Castro
14 min readDec 18, 2017

--

O desenvolvimento front-end atualmente conta com uma série de frameworks e estruturas diferentes que muitas pessoas que estão iniciando ainda não ouviram falar. A primeira vista tentar aprender React ou Angular de cara pode ser desafiador para quem só viu JQuery. Nesse meio, o Vue.js surge como uma alternativa mais simples, porém extremamente poderosa e performática.

Perto dos dois gigantes o Vue tem se saído até melhor em termos de performance, mas esse não é um post sobre as diferenças entre os frameworks. Deixo o link de algumas comparações para os curiosos:

Aprender Vue é uma jornada mais rápida em comparação aos outros dois frameworks e te ajuda a fortalecer conceitos do desenvolvimento front-end moderno como: componentes, rotas, reatividade e outros. Eu sempre recomendo aprender Vue primeiro justamente por ser mais rápido e facilitar muito na hora da transição para outro framework. Uma vez sabendo Vue é muito mais fácil entender os conceitos do React ou do Angular, seja qual for o seu objetivo. Além do mais, se você procura um framework performático, você não vai precisar de nada além do próprio Vue.js e suas bibliotecas oficiais.

O que são componentes?

Primeiramente, antes de começarmos o nosso tutorial precisamos saber o que são componentes. Simplificando o conceito, componentes são estruturas reutilizáveis com funcionalidades encapsuladas. Ou seja, elementos que possuem html, css e lógica encapsulados e que podem ser reutilizados seja dentro do mesmo projeto ou até mesmo em outros.

Por exemplo, digamos que você possua uma input de busca padrão com um botão e ele possui o mesmo comportamento e estilo em todos os seus sistemas. Na hora de utilizar esse input de busca em outra página da sua aplicação você provavelmente usaria o bom e velho ctrl+c/ctrl+v no html/css e arquivo javascript referentes a esse input. E se ele fosse um componente com tudo isso incluso? Você só precisaria importar o componente e utilizar, sem ter todo o código dele espalhado em diversos lugares.

Para entender mais afundo, recomendo a leitura desse artigo do Tableless:

Tutorial: To- Do List

Nesse tutorial vamos desenvolver o To-Do List abaixo:

To-Do List

Quando se trabalha com componentes é possível pensar de forma micro e macro. Dependendo da aplicação é necessário que cada pequeno elemento seja um componente. No nosso exemplo, vamos usar componentes macros e interagir entre eles utilizando eventos. Dessa forma, usando a estrutura do Vue.js, teremos quatro componentes:

Componentes do To-Do List

Instalação

Para desenvolver essa aplicação vamos precisar de algumas coisas instaladas:

  • Node e NPM (8.4.0)
  • Vue-cli (2.9.2)
  • Bulma (0.6.1)
  • Font-Awesome (4.7.0)

O NPM vem instalado com o Node, então só é preciso instalá-lo. O vue-cli exige pelo menos a versão 6 do Node. Você pode baixar a versão mais nova no site oficial. Coloquei entre parênteses as versões usadas por mim durante a elaboração do tutorial, se você estiver usando uma versão mais antiga ou mais nova podem haver algumas diferenças, mas acredito que isso não vá prejudicar o andamento do tutorial. Tentarei mantê-lo atualizado para evitar isso. :D Após a instalação, instale o vue-cli utilizando o código abaixo:

npm install -g vue-cli

O vue-cli possui vários templates iniciais, para conferir todos acesse o github oficial do projeto. Nesse tutorial utilizaremos o webpack simple para podermos utilizar o webpack, ES6 e outras funcionalidades.

vue init webpack-simple vue-tutorial

Após o download do template serão pedidas algumas informações, aperte "enter" para utilizar os valores padrões e escolha não para o uso do SASS, pois não utilizaremos nesse tutorial.

Configuração inicial no vue-cli

Com o boilerplate configurado, instale as dependências do projeto:

npm install

Pronto! Agora você pode rodar o servidor local com o comando abaixo e ver a tela inicial do Vue.js.

npm run dev
Tela inicial do Vue.js

Agora que sabemos que está funcionando aperte ctrl+c para desligar o servidor local e vamos instalar o resto das dependências.

npm install font-awesome bulma --save

Para habilitar o Font-Awesome e o Bulma no projeto, abra o arquivo index.html e coloque as tags de estilo dentro do <head></head> como no código abaixo:

index.html

Agora que está tudo instalado, vamos em frente. Recomendo que deixe o servidor rodando. O hot-reload já vem configurado por padrão no projeto, então você não precisa ficar modificando o arquivo e rodando o servidor para ver as mudanças. Toda vez que um arquivo for salvo o servidor será automaticamente reiniciado mostrando a mudança na tela.

Antes de começar o desenvolvimento do nosso projeto vamos explicar a organização de pastas.

Estrutura de pastas inicial do vue-cli
  • node_modules: aqui ficam todas as dependências do projeto. Tudo que é instalado pelo npm install que está registrado no package.json fica nessa pasta. Como o Bulma e o Font-Awesome, por exemplo.
  • src: essa é a pasta raíz da aplicação, aqui devem estar todos os componentes, assets e o arquivo main.js que instancia o Vue. É aqui onde todo o trabalho vai acontecer.
  • Os outros arquivos são de configuração do webpack, do babel e do git.

Caso você não tenha conhecimento sobre webpack considere dar uma olhada nesse artigo depois:

To-Do List

A primeira coisa a fazer é organizar a estrutura do nosso projeto. No arquivo main.js está a definição da instância do Vue:

main.js

Aqui uma nova instância do Vue é criada no elemento com id "app" e dentro dele o componente App.vue é renderizado. No index.html é possível observar essa div com id app dentro do body:

index.html

Os arquivos com a extensão .vue representam componentes Vue, um exemplo disso é o componente de entrada App.vue. A estrutura padrão de um arquivo .vue é composta de três elementos: template, script e style. No nosso arquivo App.vue esses três elementos estão presentes para renderizar a tela inicial do Vue. Vamos começar estilizando ele para deixar a nossa aplicação mais próxima do layout do nosso To-Do List. Delete tudo que estiver dentro dessas três tags e insira o código abaixo:

App.vue

Na tag script é onde toda a lógica desse componente acontece. Como especificado, esse componente possui um nome (name: 'app') e dados (data). Em “data” ficam representadas todas as variáveis daquele componente que o Vue precisa conhecer para utilizar. No nosso exemplo acima ele possui uma variável “msg” com valor “Hello, World!”. Como essa variável está registrada em data, eu posso utilizá-la no template da aplicação utilizando chaves duplas dentro do <h1> e chamando a variável: {{msg}}.

O Vue possui outras funcionalidades além do data como filters para a criação de filtros e methods para a criação de funções que podem ser chamadas por elementos do template, como em um evento de clicar, por exemplo. Além de diretivas condicionais e iteradores que também podem ser usados no template como v-if, v-for, v-show. Vamos explicar essas funcionalidades conforme formos usando no tutorial, caso queira dar uma olhada geral na estrutura do Vue, considere olhar a documentação oficial.

Se tudo ocorreu como o esperado você deverá ver essa imagem:

App.vue — Hello, World!

Agora que sabemos como exibir variáveis dentro de um template, vamos criar o nosso primeiro componente para exibí-lo dentro do App.vue. Para isso, crie a pasta components dentro da pasta src e crie um arquivo chamado TodoCard.vue como na imagem a seguir:

Inicialmente vamos apenas colocar o html e editar o css para termos algo próximo do que queremos. Como ainda não estamos exibindo nenhum dado, vamos apenas marcar o template com palavras para sabermos onde o dia e a quantidade de tarefas devem ser exibidos. O arquivo TodoCard.vue deve ficar assim:

TodoCard.vue

Como é possível ver, a tag script ainda não tem nada, apenas o nome do componente. Após criar o componente você percebeu que nada mudou na tela do projeto, afinal esse componente existe mas não está sendo usado em nenhum lugar. Para podermos utilizá-lo precisamos registrar ele, faremos isso no arquivo App.vue como no código abaixo:

App.vue

No início da tag script do App.vue importamos o TodoCard do arquivo TodoCard.vue e criamos uma nova chave chamada components {}. Aqui dentro registramos o nosso componente importado, o TodoCard. Agora que o App.vue conhece o componente TodoCard podemos utilizá-lo dentro do template html. Deletamos o <h1> que exibia a variável msg, inserimos alguns elementos de layout do Bulma (row, columns…) e chamamos o nosso novo componente dentro do App.vue com a tag <todo-card></todo-card>. O nome "todo-card" foi definido dentro da variável name no TodoCard.vue e utilizamos ele para chamar o componente dentro do template.

A sua aplicação deve estar assim:

Exibindo TodoCard inicial dentro do App.vue

OBS: Caso tenha ocorrido algum problema até aqui, preste atenção nas mensagens de erro do terminal onde o servidor local está rodando. Em geral os erros são bem explícitos e muitas vezes apontam com uma seta onde está o erro. Chaves não fechadas, vírgulas onde não devem existir, aspas abertas… Esses são erros comuns que acontecem durante o desenvolvimento e podem gerar uma dor de cabeça até encontrar o que estava errado.

O nosso TodoCard será o componente principal para o nosso To-Do List então nele serão criados os principais elementos da nossa aplicação. Vamos começar por três variáveis no data: dias, meses e tarefas. As duas primeiras serão utilizadas na formatação da data exibida no canto superior esquerdo do TodoCard. Para isso utilizaremos uma computed property como no código abaixo:

TodoCard.vue

Aqui definimos os dias, os meses e as tarefas em arrays. Também inserimos uma nova chave na tag script. Computed é abreviação para computed property que significa dados computáveis, ou seja, é uma variável que resulta de algum cálculo/computação. Diferente do Data que são variáveis com valor definido, mesmo que esse valor seja alterado posteriormente ele não resulta de uma função como uma computed property. No nosso exemplo pegamos uma nova data e formatamos ela utilizando os dias e meses definidos data() para exibir a data no formato: Dia da semana, dia do mês e mês. Para isso chamamos a nossa computed property como se fosse uma variável data no html: {{hoje}}. Também utilizamos o {{tarefas.length}} para exibir a quantidade de tarefas. O resultado disso na tela é:

Exibindo data formatada e a quantidade de tarefas

Na nossa figura de exemplo final do projeto definimos que teremos quatro componentes. Dois dele pertencem ao nosso TodoCard. Então vamos criar um novo componente na pasta /components chamado NovoTodo.vue. Esse componente terá o input de descrição da tarefa e um botão como no arquivo abaixo:

NovoTodo.vue

Antes a gente só estava exibindo/manipulando uma variável data que havia sido pré-definida. Aqui é possível ver uma nova estrutura do Vue chamada de v-model. Essa estrutura faz o bind entre elementos de input/select/outros com um elemento data do Vue. No nosso exemplo estamos atribuindo o que o usuário digita dentro do input à variável tarefa que inicialmente é uma string vazia.

Com o componente criado, vá até o arquivo TodoCard.vue, importe e registre o componente para poder usá-lo no template:

TodoCard.vue

Sua tela deve mostrar isso ao final:

Exibindo o NovoTodo.vue no TodoCard.vue

Para visualizar o v-model em tempo real sugiro que utilize um plugin para o Google Chrome, o Vue-Devtools. Nele você consegue clicar no componente do lado esquerdo e visualizar os dados associados a ele. Quando você digitar algo no input da nova tarefa poderá ver a variável tarefa sendo alterada como no vídeo abaixo:

O nosso input já está associando o que o usuário insere à variável tarefa. Agora como podemos adicionar essa variável no nosso array de tarefas no componente pai (TodoCard)?

A maneira mais fácil de fazer isso é através de eventos. Precisamos emitir um evento do componente filho (NovoTodo) para o componente pai (TodoCard). Mas esse evento precisa estar associado a outro evento: o de clicar no botão de adição de tarefa. Para escutar um evento, é possível utilizar a diretiva v-on no template ou a sua abreviação com o símbolo "@".

Então em vez de usarmos o "v-on:click" utilizarmos o "@click" no botão de adição. Esse evento de click irá invocar uma função chamada "enviarTarefa". Para registrar uma função no Vue é preciso inserir uma nova chave chamada "methods" e lá registrar todas as funções que iremos utilizar no nosso componente. Observe o código do NovoTodo.vue abaixo:

NovoTodo.vue

No template adicionamos o "@click='enviarTarefa'" indicando que quando houver um evento de click o método enviarTarefa será chamado. Esse método foi registrado dentro de "methods" na tag script. Dentro da função enviarTarefa() checamos se a variável tarefa do data() está vazia ou não, caso não esteja emitimos o evento chamando 'novaTarefa' passando como parâmetro a variável tarefa. Após emitir o evento limpamos o input ao atribuir uma string vazia à variável.

Como saber se funciona? Abra o Vue-Devtools e clique na aba Events do lado direito:

Eventos no Vue-Devtools

Sempre que o botão é clicado e a tarefa não é vazia um evento é enviado. Nas informações do evento na direita aparece o nome do evento, o tipo, de qual componente ele veio e o dado enviado, no caso, a tarefa. A nossa aplicação já está enviando o evento, agora precisamos receber esse evento no componente pai (TodoCard).

Já sabemos que o "@" escuta um evento e estamos emitindo um evento com o nome "novaTarefa". Então podemos escutar esse evento no componente pai com "@novaTarefa" e chamar uma função para tratar esse evento, da mesma forma que fizemos no "@click="enviarTarefa". Então vamos colocar isso no TodoCard:

TodoCard.vue

Na tag do componente novo-todo escutamos o evento e chamamos a função para adicionar uma nova tarefa:"@novaTarefa='adicionarTarefa'". Em seguida registramos essa função em "methods" e criamos um objeto nova_tarefa, afinal a tarefa precisa ter uma descrição (description) e também também um status (checked), para sabermos se ela foi finalizada ou não. Na tela da aplicação podemos ver as tarefas sendo inseridas no array de tarefas e a contagem aumentando.

Novas tarefas adicionadas no array de tarefas

O componente NovoTodo está completo. Vamos criar o nosso último e mais importante componente: TodoList. Adicione o TodoList.vue na pasta components e inicie-o com o template padrão abaixo:

TodoList.vue

Vamos ver como ficou? Importe, registre e adicione o TodoList ao TodoCard:

TodoCard.vue

A tela da aplicação deverá mostrar isso agora:

Exibindo o componente TodoList

Para exibir a lista de tarefas o componente TodoList precisa ter acesso ao array tarefas do componente pai (TodoCard). Para isso podemos usar propriedades (props) que são atributos personalizados e servem para passar dados entre componentes pai e filho. Mas que de forma fazemos isso?

Primeiramente precisamos usar o v-bind ou ":" na tag do componente, especificando qual o nome da propriedade e a que variável ela se referencia. Por exemplo:

<todo-list :tarefas="tarefas"></todo-list>

Você pode chamar o ":tarefas" da forma que preferir, mas para manter o padrão usaremos assim. Nesse código o :tarefas está indicando que estamos criando uma propriedade chamada tarefas dentro do componente TodoList e essa propriedade se referencia à nosso array de tarefas do TodoCard. Então podemos registrar essa propriedade (prop) dentro do componente TodoList e usá-la. Veja os arquivos abaixo:

TodoCard.vue
TodoList.vue

Ao registrar a propriedade em "props" o componente TodoList tem acesso à lista de tarefas de forma reativa. Ou seja, sempre que houver uma mudança nessa lista, ela também será alterada no TodoList. Veja a imagem abaixo:

Recebendo uma nova tarefa no TodoList

O TodoList possui o array de tarefas registrado em props e observa as alterações no TodoCard quando uma nova tarefa é adicionada.

Já podemos ver as tarefas no componente TodoList, agora precisamos exibí-las. Como não sabemos quantas tarefas teremos e esse valor pode ser alterado a qualquer momento, podemos utilizar a diretiva v-for para iterar sobre a nossa lista e renderizar o template padrão para cada item dessa lista. Veja o código abaixo:

TodoList.vue

Usamos a diretiva v-for na lista de tarefas. O v-for te dá acesso ao valor que chamamos de "tarefa" e ao index desse valor no array de tarefas. Usaremos o index mais a frente. Por enquanto podemos exibir a descrição dessa tarefa através do {{tarefa.description}}.

Agora podemos ver as tarefas adicionadas:

Exibindo tarefa adicionada no TodoList

Ainda nos restam duas tarefas: marcar a tarefa como "checked" e deletar. Como vimos no NovoTodo, podemos utilizar eventos para nos comunicarmos com o componente pai (TodoCard) e iremos utilizá-los para poder setar uma tarefa como finalizada e para deletar. Mas antes disso vamos definir o que essa tarefa finalizada representa.

Seguindo o nosso layout exemplo, uma tarefa concluída deverá ter um estilo com uma linha cortada. Mas como modificar o estilo de acordo com a variável checked? Podemos adicionar uma classe para todas as tarefas que tiverem checked = true usando o "v-bind:class" ou a sua versão abreviada ":class". No TodoList.vue, dentro do v-for altere a linha que exibe a descrição da tarefa para:

<p class="control is-expanded" :class="{'checked': tarefa.checked }">{{tarefa.description}}</p>

Agora além de exibir a descrição da tarefa, caso essa tarefa tenha o valor true na chave checked, ela receberá a classe "checked". Essa classe já foi definida no nosso estilo quando criamos o componente TodoList, mas ainda não está sendo usada já que ainda não alteramos o valor padrão do checked de uma tarefa.

Para fazer isso vamos escutar o evento de clique no botão do lado esquerdo da tarefa e chamar a função check que criaremos nos métodos. Como temos acesso ao index da tarefa, vamos enviar esse valor no evento para podermos identificar qual tarefa queremos finalizar:

TodoList.vue

Para checar se tudo está funcionando vamos escutar o evento "check" no TodoCard e chamar a função "checkTarefa" ("@check='checkTarefa'")para alterar o valor de true para false e vice versa sempre que o botão for clicado:

TodoCard.vue

Para fazer o nosso "toggle" na função checkTarefa usamos o index recebido no evento para identificar a tarefa no nosso array e então alteramos o valor do checked para o inverso do que estava.

Testando o resultado na nossa aplicação teremos:

Finalizando uma tarefa — toggle do botão

Nossa aplicação está quase completa! Para finalizar precisamos deletar uma tarefa, para isso usaremos eventos novamente. Dessa vez vamos escutar o evento de "@click" no botão de deletar e chamar a função "remover" passando como parâmetro o index da tarefa. Igual acabamos de fazer para finalizar uma tarefa.

TodoList.vue

Agora para deletar essa tarefa do nosso array você precisa escutar o evento no TodoCard.vue e chamar a função que chamaremos de removerTarefa. Nessa função você poderia executar o código abaixo para deletar a tarefa, certo?

delete this.tarefas[index]

Errado. Se você tentar colocar isso dentro da função removerTarefa vai descobrir que nada vai acontecer na tela. Se você inspecionar no Vue-Devtools vai perceber que o elemento foi removido do array tarefas. Mas o que houve então? Se você olhar a documentação oficial do Vue, verá que existe um tópico específico para explicar como funciona a reatividade em listas e objetos: Renderização de Listas. E devido a algumas limitações do Javascript o delete não vai ativar a renderização do componente atualizando ele. Para isso acontecer é preciso usar a função splice(). Então o nosso código deve ficar assim:

TodoCard.vue

Agora sim!

To-Do List finalizado

Concluímos o nosso To-Do List! O código final do projeto está no Github. Deixo como sugestões para a continuidade dos estudos adicionar animações com as transitions do Vue e adicionar um filtro para o contador de tarefas, renderizando o plural "tarefas" e o singular quando for mais apropriado. Tudo isso pode ser visto na documentação oficial! :)

--

--

Késsia Castro

Enthusiast of software development and diversity in IT. Consultant Developer at Thoughtworks.