Vue.js 101: uma introdução ao framework

Criado em 2014 por Evan You, o Vue.js vem recebendo bastante atenção nos últimos anos, e é sobre ele que falarei hoje. Cobrirei o básico - explicando qual é a ideia do framework, a instalação, como funciona - e até guiarei a criação de um mini app.
Felipe Kosouski | 8 de fevereiro de 2022

Já ouviu falar de Vue.js? Aposto que sim. Mas, e aí, chegou a dar uma olhada mais a fundo e a testar algumas coisas ou não? Vue.js é um framework Javascript que se intitula "Framework Progressivo", uma abordagem interessante e diferente de algumas outras do mercado.

A maneira como ele funciona consegue ser bem atrativa, principalmente pela sua simplicidade e facilidade de aprendizado. Além do mais, é uma ferramenta que está ganhando bastante espaço no mercado. O que acha de conhecer um pouco mais e até de desenvolver um mini app?

Introdução

Nos últimos anos, a programação web tem passado por uma série de mudanças. Algumas linguagens aparecem, outras se tornam menos usadas, ferramentas são criadas, tudo com o objetivo de tornar a web cada vez mais dinâmica e fluida para o usuário final e, também, mais prática e poderosa (com novos recursos para os desenvolvedores). Se você não viveu os últimos dez anos em uma caverna, sabe que, atualmente, quando se fala de web, logo vem à cabeça o Javascript.

Antes usado apenas para levar às páginas um pouco mais de dinamismo, hoje pode ser aplicado em quase tudo. Do front ao backend e até ao desktop, temos uma infinidade de ferramentas, bibliotecas e frameworks e, enquanto esse artigo era escrito, surgiram 25 frameworks novos e 109 libs. Seja para criarmos um app completo ou inserirmos um plugin de seleção de data, existe algo pronto para Javascript.

Quando se trata de frameworks JS para front end, apesar de existirem vários, normalmente encontramos três que se destacam:

  • Angular;
  • React (que, apesar de estar mais para uma lib, acaba sempre entrando junto com os frameworks devido às suas funcionalidades e às maneiras de desenvolver que possibilita); e
  • Vue.js.

Como o Vue.js vem recebendo bastante atenção nos últimos anos, inclusive com o lançamento da versão 3, é interessante ter mais uma ferramenta na manga para levar para discussão ao iniciar um novo projeto (lembrando já, desde o início, que não existe bala de prata, não existe melhor framework ou ferramenta, tudo depende da necessidade).

A ideia central deste artigo é ser basicamente um Vue.js 101, no qual cobrirei o básico explicando qual é a ideia do framework, a instalação, como funciona e até guiarei a criação de um mini app (vai ter To Do List sim…) para ajudar a explicar e fixar alguns conceitos.

O que é Vue.js

Vue.js foi criado em 2014 por Evan You depois de ele ter trabalhado para o Google com AngularJS em vários projetos. A ideia dele era se basear nas partes das quais mais gostava do Angular e criar algo bastante leve.

Atualmente, o Vue.js se encontra na versão 3, porém a grande maioria das libs e ferramentas, apesar de suportarem a versão 3, estão em beta, fazendo com que a versão 2 ainda seja a melhor escolha para projetos que precisam de um bom suporte (focaremos na versão 2 neste artigo).

Segundo a própria página oficial, o Vue.js é considerado um "Framework Progressivo". Mas que raios seria isso?

Um framework progressivo significa que você não precisa usar o conjunto inteiro de ferramentas que o framework fornece. Pode por exemplo, iniciar seu projeto utilizando-o em partes pequenas de uma aplicação - e, conforme a aplicação for crescendo, inseri-lo em outros componentes.

O que permite isso é a maneira como ele é implementado, sendo apenas um markup adicional para o HTML, basicamente um template vinculado a um data model, fazendo com que, ao atualizarmos uma propriedade do data model, o html seja automaticamente atualizado (sim, é aqui que entra a ideia de reatividade).

O Vue.js foi desenhado desde o início para ser aplicado de maneira incremental.

Comparativo do Vue.js com angular/react

É impossível não fazer comparações entre a trinca de frameworks mais populares para JS do mercado. Algumas pessoas têm mais afinidade com um ou outro, outras pessoas os defendem de maneira veemente.

Como disse anteriormente, acredito que exista a ferramenta certa para o trabalho certo. Porém, somente para se ter uma pequena ideia das principais diferenças, podemos citar as seguintes:

  • Angular: desenvolvido e mantido pelo Google, é bastante rápido e fácil de colocar algo para rodar de início, mas algumas coisas parecem mágicas demais, às vezes dificultando alguma customização maior. Possui uma codebase bem "opinionated" de como você deve construir um app.
  • React: é mais considerado uma biblioteca do que um framework. Mantido pelo Facebook, tem uma ótima performance. Trata-se de uma solução para aplicativos mobile com React Native. Entretanto, a curva de aprendizado é um pouco alta devido a como os métodos de renderização funcionam. Além disso, não é muito amigável para devs sem conhecimento de ES6+.
  • Vue.js: open source e sem influências corporativas. Boa performance, assim como a do React. Bastante flexível em como construir apps. Aprendizado fácil por oferecer mais semelhanças com o que já conhecemos de html/css/js. Infelizmente, ainda sem uma solução formal/nativa para apps cross platform.

Acredito que a grande vantagem do Vue.js é justamente o fato de ele poder ser aplicado de maneira incremental, dada organização dos arquivos .vue, divididos em tags de template, script e css, que podem ser aplicados de maneira global ou no escopo de apenas um componente. Um outro benefício é a facilidade com a qual podemos vincular um elemento HTML ao data model.

Let's Code

Bom… Less talk, more code. Agora, vamos pôr um pouco a mão na massa. Vamos passar pela instalação e pela construção de um miniaplicativo to-do list (eu sei, é clichê, mas é um exemplo muito bom). À medida que for aplicando algo diferente, vou, também, explicando o que significa e o motivo da utilização.

Instalação do Vue.js

Segundo a documentação, existem quatro maneiras de fazer a instalação e utilizar o Vue.js.

  • Direct Install: apenas fazer o download do arquivo de script e referenciá-lo no seu html utilizando uma tag de script. A variável Vue ficará disponível globalmente. Importante lembrar que é legal utilizar a versão de dev do script enquanto está desenvolvendo, pois ela inclui vários warnings e modo debug - e, claro, não usar a versão de dev em produção.
  • CDN: assim como o direct install, basta referenciar o link do cdn direto em uma tag de script no seu html.
<!--Dev-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<!--Produção-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
  • NPM/Yarn: a maneira mais indicada quando se está trabalhando em um projeto médio/grande, pois tem boa integração com webpack. Não se esqueça de instalar o node antes.

npm install vue

yarn add vue

  • CLI: O Vue fornece uma ferramenta oficial de linha de comando (CLI) para instalação e é a maneira mais indicada para criar uma estrutura completa de SPA (Single Page Application) com tudo que é necessário para um workflow de front end atual.
/ Primeiro é necessário instalar a CLI
npm install -g @vue/cli
# Ou
yarn global add @vue/cli

// Depois de instalado, podemos criar um projeto rodando
vue create nome-do-projeto

Após rodar o comando de criação do projeto pela CLI, ela nos permite escolher várias opções e configurações, como presets, typescript ou javascript, linters, formatters, router, vuex, ferramenta para testes unitários, dentre outras.

Hello Vue.js

Para nosso app, vamos utilizar a maneira mais básica e direta de instalação, que é o CDN.

Vamos, inicialmente, criar uma pasta chamada todo_app e, dentro dela, um arquivo chamado index.html e outro chamado app.js.

mkdir todo_app

cd todo_app && touch index.html app.js

Após criados os arquivos, abra a pasta no seu editor de código preferido. No arquivo index.html, vamos começar com a estrutura básica e criar uma div, que é onde será "injetado" o Vue.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js Todo App</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- Todo e qualquer html que vier aqui dentro, poderá ser utilizado com as funcionalidades do Vue.js -->
    </div>
</body>
</html>

Agora, já podemos vincular um data model ao nosso html. No arquivo app.js, coloque o seguinte trecho de código:

const app = new Vue({ //inicialização da instância Vue
el: '#app', // referência para o elemento html
data: {} // data model
})

Essa é a estrutura básica de uma instância Vue. Repare que a iniciamos e passamos a um objeto com duas propriedades (el, que é o elemento html onde essa instância será injetada) e à propriedade data. Esse data é o nosso data model.

Então, vamos colocar um texto na nossa página identificando o que é o aplicativo?

Primeiro precisamos definir uma propriedade para nosso data model. Vamos chamá-la de message.

const app = new Vue({
el: '#app',
data: {
message: "Uma super To Do List com Vue.js"
}
})

Legal, temos nosso texto dentro do nosso data model. Mas e agora? Como exibimos esse texto na nossa página?

O Vue.js utiliza uma sintaxe de template chamada mustache. Quando temos propriedades em nosso data model, podemos acessá-las no html da seguinte maneira:

{{propriedade}}

Voltando ao nosso html, primeiramente precisamos abrir uma tag de script apontando para nosso arquivo app.js. Depois, para exibirmos a mensagem na tela, basta referenciá-la dentro da div em que o Vue pode ser utilizado, que no nosso caso é a div com id #app.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js Todo App</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <h1>{{message}}</h1>
    </div>
    <script src="app.js""></script>
</body>

</html>

Repare que colocamos a tag de script que chama nosso app.js no fim da tag body, e fizemos isso para evitar que o javascript tente referenciar um elemento html que ainda não existe (poderíamos utilizar o atributo async na tag script e colocá-la logo após a cdn do Vue, mas, por simplicidade, vamos manter assim mesmo).

Ao salvarmos o arquivo e abri-lo no navegador, teremos nossa mensagem exibida na tela.

Blog post _ 08.02.2022_Vuejs 101_3.png

Agora, faça um teste e experimente mudar a mensagem do nosso data model para qualquer outro texto, salvar e recarregar a página. Voilà, temos nossa mensagem atualizada.

Consegue visualizar aonde podemos chegar com isso? Podemos criar diversas funções que podem alterar o conteúdo das propriedades do data model e fazer com que as coisas sejam exibidas/atualizadas na tela de acordo com a interação do usuário.

Todo App

Agora, para seguirmos em frente com nossa to-do list, precisamos do quê? Isso mesmo, de um campo de texto para que possamos digitar nosso to-do, um botão que faça nosso to-do ser adicionado a uma lista (além de, obviamente, uma lista para visualizá-lo).

No nosso arquivo index.html, vamos adicionar um input do tipo texto. Precisamos fazer com que o texto digitado seja visto pelo nosso data-model. Vish, complicou, né?

Lembra que comentei anteriormente que podemos vincular dados aos nossos elementos html? Inclusive inputs… E é aqui que entra uma sacada bem legal do Vue.js, pois ele possui várias diretivas, que são basicamente como atributos de uma tag html e que servem para facilitar muita coisa. Vamos conhecer agora uma das diretivas mais importantes, se não a mais importante, o v-model.

O v-model funciona como uma interligação de mão dupla com nossos dados. Se definirmos uma propriedade qualquer no nosso data-model, podemos ligá-la ao nosso input, e qualquer alteração que fizermos no campo será automaticamente atualizada na propriedade definida.

Para ficar um pouco mais claro, vamos ao código.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue.js Todo App</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
</head>

<body>
    <div id="app">
        <h1>{{message}}</h1>
        <input type="text" name="todo" v-model="todo" id="todo-input">
    </div>
    <script src="app.js""></script>
</body>

</html>

Repare que inserimos a diretiva v-model diretamente no nosso input, como se fosse um atributo da tag html. Agora, no nosso arquivo app.js, dentro do data, em seguida do message, vamos adicionar o todo e atribuir uma string vazia para ela.

const app = new Vue({
el: '#app',
data: {
message: "Uma super To Do List com Vue.js",
todo: ""
},
})

Mas por que uma string vazia? Lembra da interligação de mão dupla do v-model? Qualquer coisa que for inicializada aqui será jogada dentro do nosso input, e queremos que ele inicie vazio para podermos preencher.

Quer ver o v-model em ação? Faça o seguinte teste. Abra a página no navegador e, em seguida, abra a console. Na console, conseguimos acessar a instância Vue por meio da constante app que definimos no nosso app.js.

Antes de preencher o input, verifique o que existe dentro de app.todo, e ele deverá estar vazio. Depois, coloque qualquer texto dentro do input e verifique novamente o conteúdo de app.todo. O que foi digitado deverá aparecer na console.

Blog post _ 08.02.2022_Vuejs 101_5.png

Agora, antes de fazermos o botão que insere um item na lista, precisamos de uma lista…

Listando itens do array

Vamos ao nosso arquivo app.js e, assim como nos outros, inserir uma propriedade para representar nossa lista.

const app = new Vue({
el: '#app',
data: {
message: "Uma super To Do List com Vue.js",
todo: "",
todoList: [
"item 1",
"item 2",
"item 3"
]
},
})

O todoList é inicializado como um array contendo três itens. Nesse ponto, já conseguimos mostrar os itens na nossa página, e, para darmos continuidade ao projeto, vamos utilizar outra diretiva bastante importante do Vue.js, o v-for. Assim como um loop for em qualquer linguagem de programação, aqui ele serve para iterar sobre uma lista, seja ela de strings, de inteiros, de objetos, do que for.

No arquivo index.html, vamos adicionar o seguinte trecho logo abaixo do input.

<ul>
   <li v-for="todo in todoList">
       {{todo}}
   </li>
</ul>

O código é bastante intuitivo e não tem grandes segredos. Para cada todo em nossa todoList, queremos que ele seja impresso na tela como um elemento do tipo:

<li>

Ao salvarmos e recarregarmos a página, veremos nossos três itens na tela.

Blog post _ 08.02.2022_Vuejs 101_6.png

Feito isso, agora podemos partir para o botão de adicionar um item à lista.

Adicionando itens na lista com evento de click

Aqui, vamos utilizar duas coisas novas, uma diretiva para cuidar do evento de click no botão e uma nova propriedade da instância Vue chamada methods.

Vamos primeiro adicionar o botão. No index.html, logo abaixo do input e antes da lista, vamos inserir uma tag button, e informar que queremos escutar o evento de click, ou seja, que, ao clicar no botão, algo deve acontecer.

<button @click="addTodo">Adicionar to do</button>

A diretiva @click é responsável por dizer o que vai acontecer ao clicar no botão, nesse caso, estamos chamando o método addTodo (que ainda não existe, mas vamos criá-lo em seguida). Você pode encontrá-la como v-on:click também, pois o @ é apenas um encurtador de sintaxe.

No arquivo app.js, vamos adicionar a propriedade methods à nossa instância Vue e definir o método addTodo dentro dela, ficando da seguinte maneira:

const app = new Vue({
    el: '#app',
    data: {
        message: "Uma super To Do List com Vue.js",
        todo: "",
        todoList: [
            "item 1",
            "item 2", 
            "item 3"
        ]
    },
    methods: {
        addTodo(){
            if (this.todo) {
                this.todoList.push(this.todo)
            }
            this.todo = ""
        }
    }
})

Opa, agora complicou um pouco, não é?

Vamos lá, primeiro adicionamos a propriedade methods logo abaixo do nosso data. Dentro do methods, podemos definir quantos métodos precisarmos e que forem significativos para essa instância.

No método addTodo(), primeiro verificamos se algo foi preenchido no input; caso não, não precisamos adicionar na lista, e isso evitará adicionarmos strings vazias. Caso algo tenha sido preenchido no input, vamos adicionar a nossa lista utilizando o método push.

Note que estamos utilizando o this aqui, pois estamos referenciando propriedades da própria instância. Sem o this, não conseguiríamos enxergar essas propriedades. Aliás, como eu sei que tenho o método push habilitado? Porque lá em cima, no data, já informamos que a nossa lista é um array, e o método push serve para adicionar itens ao final de um array. Por fim, limpamos nosso todo para deixá-lo preparado para receber um novo item.

Agora, basta salvar e recarregar a página. Veremos que, ao digitarmos algo no input e clicarmos no botão, nossa lista é atualizada com um novo item.

Bom trabalho, jovem padawan. Apesar de já conseguirmos adicionar e ver itens da nossa lista, um to-do list sem a funcionalidade de marcar o que já foi feito não é lá muito útil, não é?

Marcando itens como done

Vamos primeiro pensar na lógica. Para podermos marcar um item como feito, precisamos saber se ele está feito ou não (duh… thank you captain obvious), e, para isso, seria interessante se cada item tivesse uma propriedade que nos informasse se ele está marcado como feito ou não.

Vamos refatorar um pouco nossa função addTodo e, também, a inicialização da nossa lista. No arquivo app.js, coloque da seguinte forma:

const app = new Vue({
    el: '#app',
    data: {
        message: "Uma super To Do List com Vue.js",
        todo: "",
        todoList: []
    },
    methods: {
        addTodo(){
            if (this.todo) {
                this.todoList.push({
                    task: this.todo,
                    done: false
                })
            }
            this.todo = ""
        }
    }
})

Mudamos a inicialização da lista para um array vazio, pois quem vai adicionar os itens seremos nós, então não precisamos ter nenhum lá dentro ainda.

Depois, refatoramos o método para adicionar itens, que, agora, em vez de adicionar apenas o texto na lista, adiciona um objeto que representa cada to-do cadastrado. Essa representação contém, além do texto, uma indicação de que aquele item adicionado está feito ou não. Inicialmente, ao adicionarmos um item à lista, ele será tratado como não feito.

Agora, no arquivo index.html, vamos adicionar um checkbox para marcar as tarefas que já foram concluídas.

<ul>
    <li v-for="todo in todoList">
         <input type="checkbox" v-model="todo.done">
         <span>{{todo.task}}</span>
    </li>
</ul>

Novamente fazemos uso do v-model para estabelecer aquela interligação de mão dupla com nosso data-model. Repare também que, como mudamos a maneira como nosso item é representado, precisamos acessar suas propriedades internas tanto no v-model quanto ao chamar entre as chaves.

Ao recarregarmos a página, inserirmos um item e marcarmos o checkbox dele, podemos verificar na console que a propriedade done daquele item será alterada para true.

Blog post _ 08.02.2022_Vuejs 101_8.png

Se desmarcarmos o item e verificarmos na console, estará novamente como false.

Classes CSS dinâmicas

Para deixarmos um pouco mais estilosa a nossa lista, o que acha de fazermos o Vue decidir se aplica uma classe css ou não? Existe uma outra diretiva chamada v-bind, que basicamente permite que executemos um trecho de código javascript que retorne verdadeiro ou falso dependendo de uma condicional.

Então, vamos fazer o seguinte: abaixo da última tag script do head do arquivo index.html, vamos adicionar uma tag de estilo que servirá apenas para aplicarmos uma linha no meio do texto.

<style>
        .active{
            text-decoration: line-through;
        }
</style>

Agora, queremos que essa classe seja aplicada somente se a propriedade done de um item estiver definida como true. Para isso, podemos alterar a tag span, que mostra o texto do item da seguinte maneira:

<span class="" :class="{active: todo.done}">{{todo.task}}</span>

Aqui, inicializamos o atributo class da tag vazio, pois não queremos nenhuma alteração de estilo se o item não estiver marcado como feito. Em seguida, definimos novamente o atributo class, porém utilizando o v-bind (o :class é apenas uma maneira mais simples de escrever v-bind:class) e passamos para ele um objeto com o nome da classe a ser aplicada e a condicional. Nesse caso, a classe css .active somente será aplicada caso a propriedade todo.done seja verdadeira.

Ao recarregarmos a página e testarmos novamente marcar um item como concluído, vamos ver que será aplicado um tachado por cima apenas do item concluído.

Blog post _ 08.02.2022_Vuejs 101_9.png

Listando apenas itens concluídos

Para fecharmos nosso mini app com chave de ouro, seria legal se conseguíssemos mostrar uma nova lista, porém apenas com os itens que marcamos como concluídos.

Para fazermos isso, vamos conhecer uma nova e muito importante diretiva, o v-if. Nesse ponto você já deve ter entendido o que ele faz: se o v-for funciona como um loop for, o v-if funciona como um if tradicional.

No arquivo index.html, vamos adicionar uma nova lista utilizando o v-for e o v-if em conjunto, pois queremos iterar sobre todos os itens, porém mostrar apenas os que estiverem concluídos.

<hr>
<h2>Concluídos</h2>
<ul>
    <li v-for="todo in todoList" v-if="todo.done">{{todo.task}}</li>
</ul>

Aqui coloquei apenas uma tag hr e um h2 para separar a página - e, seguindo a mesma ideia da outra lista, iteramos sobre ela com o v-for (utilizo o v-if para verificar qual dos itens está feito).

Ao recarregarmos a página, teremos o seguinte resultado:

Blog post _ 08.02.2022_Vuejs 101_10.png

Repare que, na lista de baixo, estão de fato aparecendo apenas os itens concluídos.

Pronto, temos nosso to-do app completo, com as funcionalidades básicas que um to-do app precisa ter. O melhor? Conseguimos desenvolver super-rapidinho graças ao Vue.js, que facilita bastante nossa vida.

Bônus - Vue Dev Tools

Gostaria de deixar aqui um bônus para quem chegou até o fim do post, uma dica valiosa para desenvolvedores Vue e para quem quer se aventurar pelo framework.

Existe uma extensão para Chrome e Firefox chamada Vue Dev Tools. Essa extensão facilita muito o desenvolvimento, pois nos ajuda a ter acesso rápido às informações do nosso data model.

Podemos utilizá-la em vez da console do navegador para visualizarmos valores atribuídos e, inclusive, alterá-los para vermos como nosso app se comporta. Vale muito a pena utilizar no dia a dia; para projetos maiores e mais complexos, se torna indispensável.

Blog post _ 08.02.2022_Vuejs 101_11.png

Só tem um detalhe aqui: para ela funcionar em um arquivo estático, precisamos ir até as configurações da extensão e habilitar o campo "Permitir acesso a URLs de arquivo". Caso contrário, a extensão não funcionará. Se estiver utilizando um servidor de desenvolvimento (servir o projeto pela CLI, por exemplo), não é necessário habilitar esse campo.

Conclusão

Ufa, chegamos até o final. Acabei me empolgando um pouco no post, mas espero ter conseguido explicar de maneira direta para que todos consigam entender. 

O Vue.js é um framework bastante poderoso, simples e intuitivo de se trabalhar, e isso se deve basicamente à sua própria proposta. É possível, com ele, criar desde aplicações simples até aplicações supercomplexas envolvendo integrações com APIs externas, autenticação e autorização, rotas, controle de estado, componentização e muito mais.

Além disso, o Vue.js tem uma comunidade muito fervorosa e prestativa e que sempre está trabalhando em melhorias - e sua documentação é bastante fácil e bem escrita (inclusive em português), sendo que lá existe bastante informação sobre o framework, como aplicar cada diretiva, o que cada uma faz, quando usar ou não usar algo, diversos exemplos simples e complexos e por aí vai.

A ideia desse post era funcionar como uma introdução e ajudar com um pontapé inicial para quem quer se aprofundar mais nesse framework tão satisfatório de se trabalhar (e que, apesar de não ser tão popular quanto React, é uma ótima opção que conta com cada vez mais vagas no mercado).

Felipe Kosouski
Aficcionado por tudo que envolve tecnologia. Amante de games, música, cafés, cervejas, RPG, artes marciais, suspenses e terror. Jogador de Airsoft aos domingos pela manhã.