Blog do Matheus Castiglioni | Criando Componente Com Shadow Dom
Sim, eu sei, Shadow DOM está um pouco ultrapassado, talvez seu uso seja muito pouco, porém, nesse post vou explicar como ele funciona e vamos criar um componente (também chamado de web component), em outras palavras, seria uma tag customizada que irá renderizar um código HTML conhecido pelo browser.
Afinal de contas, o que é esse tal de Shadow DOM? Para o que ele serve? Quando devíamos usá-lo? Calma, essa e outras perguntas é o que eu tentarei responder ao decorrer do post.
Se você está se perguntando: "Shadow DOM está ultrapassado, poucos devem utilizá-lo, então porque falar dele?". Esse post é apenas uma base para que você entenda a diferença entre Shadow DOM e Virtual DOM (assunto do próximo post, sim, um pequeno spoiler).
Se você não tem interesse em entender como ele funciona ou para o que serve, fique a vontade em não lê-lo e aguarde o próximo sobre Virtual DOM.
O Shadow DOM trata-se de uma API dos browsers (navegadores) com ela é possível anexar/adicionar um DOM separado para um elemento existente na página de forma escondida, calma, logo as coisas irão fazer sentido.
Pense o seguinte: Hoje trabalhamos muito com componentes, bibliotecas como o React, Angular e Vue fazem uso excessivo deles (cada uma do seu jeito, mas no final, praticamente tudo é um componente). Na web também temos os famosos web components, mas, o que seria esses "componentes"?
Para um melhor entendimento e simplicidade do post, entenda de forma resumida que componentes são tag's HTML ou elementos que não existem, ou seja, o navegador nativamente não os conhecem, mas, de alguma forma ele irá renderizar e criar um HTML conhecido, com as tag's nativas.
Concluindo, através do Shadow DOM conseguimos criar tag's customizadas e "transformá-las" em tag's nativas.
Apenas para solidificar, podemos usar o Shadow DOM para criar componentes, também chamados de web components, além disso, também é possível aplicar estilos para elementos específicos na página sem refletir nos demais.
Finalmente, hora de começar a criar nosso primeiro web component.
O primeiro passo será definir qual componente vamos criar, para o exemplo do post será um componente de mensagem. Agora com o componente definido, devemos criar uma classe para representá-lo:
Mas, onde essa classe será salva? Para escrever os códigos do nosso componente vamos criar um arquivo JavaScript chamado Mensagem.js, todos os seus códigos devem estar dentro desse arquivo. Aproveite que o arquivo acabou de ser criado e já faça a importação dele em seu HTML:
Continuando a implementação e criação do nosso componente, até o momento criamos uma simples classe, mas, precisamos transformá-la em um elemento HTML (para que ele possa utilizar as funções do HTML), como podemos fazer isso? Podemos utilizar a herança e herdar da classe HTMLElement:
Através da palavra extends é possível realizar herança em JavaScript.
Agora, precisamos implementar como e o que será nosso componente, nossos códigos irão ficar dentro do construtor (constructor) (mais para frente irei explicar o porque):
Devemos chamar o construtor da clase mãe, ou seja, da classe HTMLElement, isso é feito através do super().
Legal, o primeiro passo será de fato criar um Shadow DOM, podemos fazer isso através da função attachShadow:
Aqui, estamos criando e adicionado um shadow root para nosso componente, a opção mode serve para definir se nosso shadow root pode ser acessado fora do componente, ou seja, de forma global em nosso JavaScript, com o valor definido como closed isso não será possível, apenas nosso componente consegue interagir e acessar o shadow root.
Agora precisamos criar nossa tag conhecida pelo HTML, para ser renderizada pelo nosso componente, para isso podemos utilizar a velha conhecida createElement:
Para o exemplo, vamos renderizar um parágrafo (p). Além do componente, vamos adicionar algum estilo também:
Pronto, temos nosso elemento e estilo criado. Agora precisamos passá-los para nosso shadow root, isso pode ser feito através da função appendChild:
Adicionamos como filhos do shadow root nosso estilo e mensagem. Por fim, precisamos registrar nosso componente e definir uma tag para ele, isso pode ser feito através da função customElements:
Para definir nosso componente devemos informar dois parâmetros:
Passar um nome para ele, esse nome será a tag dele
Obs: Lembra quando eu falei para adicionarmos nossos códigos dentro do construtor (constructor) da nossa classe? Isso foi necessário, porque a função .define invoca o construtor da classe passada para ele.
Mas, algo deu errado, veja com ele foi renderizado:
Repare que ele está sem conteúdo, mas ele deveria mostrar nossa mensagem: Olá Shadow DOM, o que está acontecendo? Em nenhum momento definimos o conteúdo do nosso componente, para isso, podemos utilizar a função .textContent:
Dessa maneira estamos falando: Pega o .textContent da tag customizada e passa para nosso componente que será renderizado pelo shadow root. Agora se voltar no navegador e recarregar:
Agora tudo está funcionando.
Lembra que eu falei que era possível definir um estilo apenas para nosso shadow DOM? Pois é, para ver isso na prática vamos adicionar outro elemento na página com a mesma classe da nossa mensagem:
Sabemos que nosso componente app-mensagem irá renderizar um parágrafo com a classe mensagem, vamos ver como ficou o HTML renderizado:
O Shadow DOM foi muito legal e bastante utilizado, apesar de muitos o terem substituídos pelo Virtual DOM, acho bem legal a forma como ele funciona, dá para fazer altas brincadeiras (rsrsrs).
E aí, você já conhecia o Shadow DOM? Não deixe de comentar e se gostou do post e quiser receber novidades por email, se increva na newsletter.
Caso tenha necessidade, o projeto feito para o exemplo do post pode ser encontrado aqui em meu github.