Neste guia veremos o que são web components, quando usar, sua estrutura e também um crash course criando um web component do zero que é um card Pokémon, com vários recursos interessantes.
Web Components são elementos customizados reutilizáveis construídos com diferentes tecnologias para serem utilizados em aplicações web.
Você já desenvolveu com Angular, Vue.js ou React? Uma das grandes vantagens da utilização desses frameworks é a reutilização do código, através de componentes customizados. Agora imagine todo esse poder usando HTML, CSS e JavaScript sem precisar utilizar nenhum framework, é nesse momento que surgem os web components.
Os web components são formados por três principais tecnologias que usadas em conjunto permitem criarmos componentes reutilizáveis mas também encapsulados, evitando conflito de código.
Elemento customizado é a possibilidade de criarmos um elemento por exemplo <andre-felizardo></andre-felizardo>
através de APIs do Javascript que permitem definir comportamentos para esse elemento.
Primeiro precisamos entender o que é DOM.
Document Object Model é uma plataforma que representa como as marcações HTML (entre outras) são lidas e organizadas pelo navegador que você usa. Depois que são carregadas (indexadas) as marcações se transformam em elementos de árvore, que podemos manipular via API.
Entender como essa árvore é construída possibilita que possamos criar códigos CSS e Javascript mais performáticos, por exemplo.
Voltando ao Shadow DOM, ele cria um DOM Fantasma, encapsulado (dentro) do elemento customizado que criamos e é renderizado de forma separada do DOM principal. É esta tecnologia que permite manter os recursos do elemento customizado privados, podendo escrever CSS e Javascript sem causar conflitos em outras partes do documento.
Para escrever os componentes temos os elementos <template>
e <slot>
que permitem criar templates de marcação que não serão exibidos na página mas poderão ser reutilizadas se tornando modelo da estrutura de componentes customizados.
A mais de 6 anos eu leio e ouço que os web components são o futuro, mas atualmente várias das features já funcionam nos browsers, então, web components são o presente! Vamos dar uma olhada no Can I use e ver como está a compatibilidade dos navegadores com essas funcionalidades.
Em geral, web components são adotados por padrão no Firefox (a partir da versão 63), Chrome, Opera e Edge (versão 80). Safari suporta apenas algumas features (ê Apple –‘).
ALERT: Pra acompanhar melhor o tutorial a seguir, é importante que você tenha conhecimento básico em HTML, CSS e Javascript.
<poke-card></poke-card>
.this.innerHTML = 'PokeCard';
window.customElements.define('poke-card', PokeCard);
Depois de salvar no navegador, a aparência deve ser essa aqui:
Primeiro vamos alterar o HTML, para que o nosso componente receba o nome do Pokémon. Adicione no nosso componente um atributo name com o valor Pikachu.
Dentro da nossa classe no Javascript, abaixo da chamada de super() vamos primeiro armazenar o valor passado no atributo em uma constante com o comando const name = this.getAttribute('name')
e depois passar essa constante para o template do nosso componente com this.innerHTML = name
Depois disso o resultado final deve ser esse aqui:
Podemos evoluir o componente da mesma forma como estamos desenvolvendo, porém se não encapsularmos o componente, podemos ter problema de CSS onde por exemplo uma regra interna ao nosso componente alteraria também os elementos externos ao componente. Então antes de começarmos a escrever CSS, vamos encapsular nosso componente, usando Shadow Root.
this.attachShadow({ mode: 'open'});
Deixe o código antigo, após super() para baixo desses novos comandos.this.shadowRoot.appendChild(template.content.cloneNode(true));
Antes da declaração da classe, vamos criar uma constante com o nome de template, e fazer ela receber um novo elemento template com o comando const template = document.createElement('template');
Dentro dessa constante template construiremos nosso HTML e CSS, passando o código usando o comando template.innerHTML
.
Depois, voltando ao código dentro da nossa função construtora, após receber o atributo nome e armazenar numa constante, vamos jogar o conteúdo dentro do h3 que escrevemos acima com o comando this.shadowRoot.querySelector('h3').innerText = name;
O resultado esperado é:
Vamos alterar o HTML para nosso card ter uma imagem. Assim como fizemos com o atributo name, crie no HTML do card um atributo avatar e passe nele a URL de uma imagem.
Depois copie o card e coloque o nome de outro Pokémon e outra imagem.
No nosso arquivo Javascript, vamos colocar uma largura para imagem no CSS, e também colocar uma tag img vazia antes do h3 que inserimos anteriormente.
Dentro da nossa função construtora, vamos fazer parecido com o que fizemos com o h3 para inserir a URL na imagem.
Primeiro vamos armazenar o valor do atributo em uma constante com o código const imageURL = this.getAttribute('avatar');
Após vamos inserir o valor dessa constante na imagem com o código this.shadowRoot.querySelector('img').setAttribute('src', imageURL);
E o resultado esperado é esse aqui:
O objetivo num é focar no CSS, então apenas copie (ou crie sua própria estilização).
Usar um slot torna nosso componente mais flexível. Utilizaremos ele para adicionar o peso e altura do Pokémon.
No HTML, dentro da nossa tag customizada adicione <span slot="height">0.4 m</>
e <span slot="weight">6.0 kg</span>
. Faça isso para os dois cards. O valor que colocamos dentro do atributo slot é o nome que estamos dando a ele.
No arquivo Javascript, vamos alterar o conteúdo do template. Abaixo do h3 colocaremos uma div com a classe info e dentro dessa div dois paragrafos um para a altura, outro para o peso. Dentro de cada parágrafo escreveremos uma legenda e criaremos um span com o slot se referenciando ao seu conteúdo do HTML.
Tudo correto, a visualização esperada é:
Vamos adicionar um botão dentro da div info para esconder ou exibir a info do Pokémon (altura e peso).
Repare na linha 37 (botão) e na linha 19 onde começa o CSS do botão no print abaixo.
ConnectedCallback é uma função que todo web component tem. Ela é chamada toda vez que o componente é adicionado ao DOM. Dentro dela vamos adicionar um escutador pro evento de clique do botão this.shadowRoot.querySelector('#toggle-info').addEventListener('click', () => this.toggleInfo());
Em paralelo vamos criar a função toggleInfo que chamamos no click. A princípio vamos apenas colocar um console.log dentro da função.
DisconnectedCallback é o oposto da função acima, ela é chamada toda vez que o elemento customizado é removido do DOM. É uma boa prática remover escutadores dentro dessa função, e é isso que vamos fazer com o código this.shadowRoot.querySelector('#toggle-info').removeEventListener();
Com isso feito, clicando no botão do card, ele deve exibir uma mensagem no console.
Agora é só a cereja do bolo. Dentro da função construtora abaixo do super() vamos criar uma propriedade da nossa classe com o código this.showInfo = true;
É essa variável que vai controlar quando vamos exibir ou ocultar as informações do Pokémon.
Dentro da função toggleInfo vamos criar uma lógica básica de trocar a propriedade display da div e trocar o texto do botão.
E pronto! Nosso elemento customizado está funcionando lindamente 😉
Eu coloquei esse código também no Github, e se você clicar em commits você pode ver a evolução do codigo, passo a passo, como foi explicado aqui no texto.
Web Components não são o futuro, são o presente.
Dúvidas, sugestão? Deixa aí nos comentários.
Desvendando o Potencial da Blockchain e Criptomoedas através da Criptografia Em um mundo onde a…
O deploy de uma aplicação React é uma etapa crucial para disponibilizar sua criação na…
Satellite 2020 foi a primeira conferência virtual do Github. O Github já tinha sido liberado…
A alguns anos atrás escrevi um texto sobre o que é o frontend, também palestrei…
O que é SVG é a sigla para Scalable Vector Graphics que traduzindo seria gráficos…
Quando você começa a trabalhar com grandes projetos de front-end, os arquivos CSS vão crescendo,…