Descomplicando os Single File Components do Vue.js

Keep calm and learn Vue.js

Vue.js sem sombra de dúvida é o framework JavaScript da vez. Segundo JavaScript Rising Stars, este carinha está no topo da lista dos FWs JS mais usados do momento. Toda essa popularidade vem, segundo a minha humilde opinião, da simplicidade que o Vue tem para resolver certos problemas e também sua simplicidade na forma de trabalhar. Este artigo tenho como objetivo expor como é simples lidar com os famosos Single File Components (SFC), arquivos com a extensão .vue que trazem uma solução muito inteligente para se lidar com os Web Components (WC).

Tá perdido, não sabe o que são Web Components, nem mesmo os Single File Components? Então te convido a ler este humilde artigo, e não esquece de recomendá-lo, viu?


O que é Vue.js?

Vue.js é uma biblioteca JS para a construção de componentes web. Ela não segue ‘a risca’ as especificações do WC, porem, se utiliza de sua filosofia.

Basicamente, com o Vue.js você já estará desenvolvendo para a web utilizando a filosofia do WC. Ou seja, você irá utilizar “shadow DOM”, em que o que estiver dentro do componente, não irá vazar dele. Você poderá usar custom tags, nomeando a sua vontade os componentes entre outras coisas. Ou seja, ele te oferece um ecossistema simples para você usar e abusar do que a web components pode te oferecer.

Para quem ainda não sabe o que são Web Components, recomenda esta leitura do site do Tableless sobre o assunto e esse Getting Started do site webcomponents.org.

Mas como o Vue.js resolve o problema de criar os componentes? Aí que entra os SFCs.

O que são Single File Components?

Esta feature do Vue.js demonstra o quanto esta lib nos ajuda a desenvolver utilizando WC. Pense comigo.

O que seria um componente web? Seria a menor parte de nossa interface, com suas próprias características e comportamentos. Sendo assim, ela traria em seu escopo, HTML, CSS e JS. Correto? Os SFCs são nada mais nada menos, que arquivos com extensão .vue em que você escreve HTML, CSS e JS juntos. O texto sobre componentes do Vinicius Reis pode elucidar algumas coisas, recomendo a leitura.

Mas Emanuel, eu aprendi que é uma boa prática a separação de responsabilidades no lado do Front-End, com arquivos .html, .css e .js. Cada um no seu quadrado, para que possa haver reaproveitamento de código. Você não está errado. Mas a WC faz com que você procure unir as responsabilidades, pois como diz o ditado popular: “a união faz a força, e também o açucar”.

Brincadeiras a parte, pense em uma UI bem complexa. Em que há dezenas de componentes em sua página, cada um com comportamento próprio. Bem, eu poderia escrever a bagaça toda em um único arquivo js com uma das formas de se criar componentes com Vue.js. (Este texto explica de maneira bem resumida formas de criar estancias de componentes com Vue.js). Todavia, temos os SFCs, que nos ajuda e muito neste momento. Pois com a chegada do Vue.js 2 e a implementação do VirtualDOM nele, os SFCs são a forma mais simples e modular de se trabalhar. O texto sobre Render Functions do Ígor Luiz elucida muito bem o que é o VirtualDOM e porque os SFCs são bons neste momento.

Se eu ainda não te convenci, não deixe de continuar lendo este texto. Possivelmente você irá se convencer de que usar Vue é muito simples e poderoso.

Para servir de exemplo do funcionamento dos SFCs, estarei usando o meu projeto de TCC do Curso Técnico, que se encontra neste repo do Github.

Single File Components, como coloquei acima, são arquivos com extensão .vue e que tem, em sua estrutura, as tags template, style e script:

<template>
Seu HTML
</template>
<script>
Seu JS
</script>
<style>
Seu CSS
</style>

Há um ponto importante a se consider sobre os SFCs: eles aceitam pre-processadores CSS — Sass, Less — , JS, CofeeScript, e HTML, como o Pug. Ou seja, além de você usar todo o poder de encapsulamento dos componentes, você pode usar a ferramenta de compilação de código que você já usa e abusa.

Por fim, antes de continuarmos, é importante comentar que os arquivos .vue não são interpretados pelo seu navegador, ou seja, é necessário utilizar uma ferramenta para passar os dados dos arquivos .vue para arquivos .js e acrescentar aos arquivos html e css finais. Para tanto, a equipe do Vue.js desenvolveu algumas alternativas para os modules bundlers mais famosos, Webpack e Browseryfi: o vue-loader e o vuefy, respectivamente. Não sabe o que é um module bundler? Dá uma olhada neste texto do Vinicius Reis. Mas Emanuel, como vou configurar estas ferramentas para que eu possa utilizar todo o poder do SFCs? A equipe do Vue.js já cuidou disso. Conheça os templates do vue-cli. Eu gosto do webpack full. Há um texto muito bom sobre os templates do vue-cli. Dê uma olhada!


Entendendo o que tem nos SFCs e como utilizá-los

Agora, que você já entendeu o que são SFCs, seu esqueleto e utilidade, vamos nos ater a cada parte do arquivo.

Entendendo a tag template

Se lembra das custom tags que mencionei acima? Elas são parte da spec da WC. Com esta spec é possível fazer duas coisas muito legais:

  • Dar um nome que você desejar — claro, não pode o que já existe, por exemplo, main, article…;
  • Construir tags da forma mais customizada possível. Já imaginou construir seu próprio slider mega boladão? Ou até mesmo um menu off-canvas completasso?

Sim, isto é possível com o SFC. Dentro da tag template há as divs, buttons, asides, sections que compõem o componente que você quiser criar, inclusive outros componentes. Tá, mas aonde entra a custom tag? Na hora que você chamar seu componente dentro da tag template do componente pai você vai dar o nome que quiser. Vamos a um exemplo, primeiramente um componente filho qualquer:

<template>
<div>
<p> Eu sou um componente filho </p>
</div>
</template>

E agora tenho também um componente pai:

<template>
<div>
<MySoon></MySoon>
</div>
</template>
<script>
import MySoon from './MySoon'
export default {
components: { MySoon }
}
</script>

Será renderizado ao final:

<div>
<div>
<p> Eu sou um componente filho </p>
</div>
</div>

Entendendo a tag style

Já imaginou criar aquele slider mega boladão e poder desenvolver ele com estilo e características próprias, sem se preocupar com que uma declaração CSS possa ‘fazer da sua vida um inferno’ por um minuto, ou horas, quando afeta toda a página? Pois bem, isso é possível com o SFC. E é bem simples, utilize o atributo scoped na tag style. Vamos ver um exemplo:

<template>
<div>
<p class="paragraph"> Meu estilo não escapará </p>
</div>
</template>
<style lang="sass" scoped>
.paragraph
color: red
</style>

Vamos aos detalhes:

  • É possível especificar uma lang, ou seja, eu posso dizer para o compilador do Vue: o código abaixo será escrito em Sass. Por default, o valor é ‘css’.
  • Com o atributo scoped, eu estou dizendo para o compilador do Vue: estas características não podem escapar deste componente. Aqui “simulamos o shadow dom”. Um DOM escondido, que contem sua própria marcação e estilo e mais para frente veremos o comportamento.

O resultado do código acima será mais ou menos esse, dê uma olhada na doc:

<div>
<p class="paragraph" _vjkla09> Meu estilo não escapará </p>
</div>
<style>
.paragraph[_vjkla09] {
color: red;
}
</style>

Entendendo a tag script

Bem, talvez a maior mágica dos Single File Components está dentro desta tag. Aqui você colocará todo o comportamento do seu componente, seja uma request ajax, um botão que invoca uma modal, que valida um form. Tua imaginação é o limite!

Ela tem esta forma:

<script>
export default {}
</script>

Bem, se tu não sabe o que quer dizer export default ali em cima, dê uma olhada nestes links:

Um detalhe importante: Vue.js te encoraja a desenvolver utilizando a sintaxe do EcmaScript 2015 ou o ES6. Por isso esse export … É a sintaxe para exportação de módulo. A parte boa é que os templates oficiais do vue-cli, tirando o simple, já trazem um module bundler e o Babel para deixar seu código compatível com os navegadores não tão modernos.

Antes de eu falar do que entra neste export, irei comentar o que vem depois. Geralmente, você irá importar algum módulo ou outro componente, que você queira usar. Mas não para por ai. Lembre-se, dentro da desta tag você pode escrever o código JS que quiser!

Bem, agora vamos nos ater ao que vem dentro do export default{}. A primeira vista é um objeto. Mas o que tem dentro deste objeto. Se você conhece um pouquinho de Vue.js ou já deu uma olhada no Hello Wolrd da documentação, deve ter visto um código parecido com isso:

<script>
const app = new Vue({
...
})
</script>

Bem, quando eu faço export default, é como se eu fizesse um export new Vue({}). Ou seja, o que está dentro de {} são os nossos objetos ou métodos de um instancia de Vue.js. Há um texto do Fábio Vedovelli sobre o que tem dentro do objeto Vue ali em cima. Não deixe de dar uma olhada.

Vamos a cada parte:

  • data: são os dados que circulam no componente. Um dos pontos da reatividade do Vue.js está neste método. Lembre-se: data, num componente .vue, deve ser uma função que retorna um objeto. Nos acusará um erro, caso eu coloque um objeto diretamente.
export default {
data () {
return {
msg: 'Use uma função, não um objeto diretamente'
}
}
}
  • props: são dados que vem do componente pai. É um array. Uma prop, no componente pai, é colocada no componente como se fosse um atributo. Vamos a um exemplo:
<!-- No componente pai -->
<MySoon title="Titulo...">
<!-- No componente filho -->
export default {
props: ['title']
}
  • computed: são dados que são calculados a partir de outros dados. Um exemplo para nos ajudar é o componente FormReturnedBook.vue, no meu projeto:
<template>
<p> Dados do livro emprestado </p>
<ul>
<li v-for="(value, key) in bookReturned"> {{ key }} - {{ value }} </li>
</ul>
</template>
<script>
export default {
computed: {
bookReturned () {
return Object.assign({}, {
Titulo: this.book.titulo,
Autor: this.book.autor,
Editora: this.book.editora,
Prateleira: this.book.prateleira,
Estante: this.book.estante,
Código: this.book.codigo,
Estoque: this.book.estoque
})
}
}
}
</script>

No exemplo acima, o this.book é uma prop que vem de um componente pai. Quando este componente recebe o conteúdo da prop book, ele passa para bookReturned um ‘map’ do objeto.

  • watch: usado para assistir a modificações do data do componente e reagir a elas. A diferença para computed é que este reage as mudanças e as utiliza para computar, criar outros dados. Por isso que as propriedades do objeto computed não são as mesma do data. Um exemplo é este componente do meu sistema:
import { isNameValid } from '../../../helpers/validates'
export default {
props: ['placeholder', 'label'],
watch: {
name () {
if (this.name === '') {
this.className = ''
this.classNameHelp = ''
this.nameHelp = ''
} else if (!isNameValid(this.name)) {
this.className = 'fa-warning'
this.classNameHelp = 'is-danger'
this.nameHelp = 'Nome inválido! Somente letras serão aceitas, sem acentos nem cecidilha'
} else {
this.className = 'fa-check'
this.classNameHelp = 'is-success'
this.nameHelp = 'Nome válido!'
}
this.$emit('sendData', this.name)
}
}
}
  • methods: são os métodos no componente, por exemplo, quando chamamos em um v-on:click da vida. Não tem muito mistério.
  • filters: são os filtros do meu componente. Para quem não sabe, com a chegada do Vue.js 2 não há mais filtros nativos, como o capitalize, uppercase ou orderBy. Porem, há uma facilidade muito grande para criá-los, de acordo com a sua vontade. Vamos a um outro exemplo, agora em um outro componente do meu sistema:
import { returnGenre, returnDidatic, returnSchool } from '../../../helpers/filters'
export default {
filters: {
didatico (value) {
return returnDidatic(value)
},
literario (value) {
return returnSchool(value)
},
genero (value) {
return returnGenre(value)
}
}
}

Lembrando que o uso dos filtros é:

<p> {{ Dado | filtro }} </p>

Bem, estas são as principais propriedades num SFC. Há outras, como o mounted. Há alguns plugins que podem ser acessíveis dentro do componente, como o router, vuex


Bem pessoal, este foi mais um texto sobre o Vue.js. Espero que tenham gostado e que ele possa ajuda-los como referência. Até a próxima!

Like what you read? Give Emanuel G de Souza a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.