DEV Community

Ana Luiza Pardini
Ana Luiza Pardini

Posted on

Guia de Components - para quem tem pressa!

Um Shadow Dom como é mais conhecido os componentes no JS Vanilla, são como cápsulas que contém seus elementos com escopo próprio, e que também é possível escolher se quer que ele seja editável ou não variando o seu mode entre “open” ou “closed”.

Uma base simples


class Component extends HTMLElement {
  constructor() {
    super(); // Chamar o construtor da classe pai (HTMLElement)
    this.shadowDom = this.attachShadow({ mode: "open" });

    // Criar o elemento h1 dentro da sombra
    const componentRoot = document.createElement("h1");
    componentRoot.textContent = this.getAttribute("title"); // propiedade

    // Estilizar o componente
    const style = document.createElement("style");
    style.textContent = `h1 { color: red; }`;

    // Adicionar elementos à sombra
    this.shadowDom.appendChild(componentRoot);
    this.shadowDom.appendChild(style);
  }
}

// Registrar o elemento personalizado
customElements.define("my-component", Component);

Enter fullscreen mode Exit fullscreen mode

Chamando dentro da página:


<script src="./src/Components/CardNews.js" defer></script>

Enter fullscreen mode Exit fullscreen mode

⚠️ O defer é importante para que o component seja carregado apenas depois que o dom da página se carregue.

<———- ————->

✨ Ainda melhor!

Para melhorar e deixar o código do componente mais limpo, você pode seguir algumas práticas e simplificações!

  1. Use aspas consistentes para atributos de strings;
  2. Utilize a notação de template literals para melhorar a legibilidade de strings longas;
  3. Separe o estilo CSS em uma string de template literal;
  4. Use o build() e styles() para organizar os códigos de construção e estilização;

class ComponentExpert extends HTMLElement {
  constructor() {
    super(); // Chamar o construtor da classe pai (HTMLElement)
    this.shadowDom = this.attachShadow({ mode: "open" });
    this.shadowDom.appendChild(this.build());
    this.shadowDom.appendChild(this.styles());
  }

  build() {
    const componentRoot = document.createElement("div");
    componentRoot.classList.add("root");

    const childDiv = document.createElement("div");
    childDiv.classList.add("child");

    const titleDiv = document.createElement("h1");
    titleDiv.textContent = `Hello ${(this.getAttribute("name") || "World")}`;

    const linkDiv = document.createElement("a");
    linkDiv.textContent = "Link Util";
    linkDiv.href = this.getAttribute("link") || "https://linkdefault.com.br";

    childDiv.appendChild(linkDiv);
    childDiv.appendChild(titleDiv);

    componentRoot.appendChild(childDiv);

    return componentRoot;
  }

  styles() {
    const style = document.createElement("style");
    style.textContent = `
      .root {
        width: 100%;
        background-color: #dedede;
      }

      .child {
        width: 50%;
        background-color: pink;
      }

      .child h1 {
        color: #dedede;
      }
    `;

    return style;
  }
}

customElements.define("component-card", ComponentExpert);

Enter fullscreen mode Exit fullscreen mode

É uma boa conduta em uma props definir um valor padrão para ela, para caso os dados não sejam carregados ou o usuário não tenha enviado os parâmetros.

🔍 Usando functions ao seu favor!

As funções vieram para ser usadas de forma que facilite o trabalho e legibilidade do código, então é importante utiliza-lá para deixar seu código mais funcional!

Neste código eu usei algumas formas de armazenar valores, concatenar e validar, além de usar a desestruturação a meu favor no objeto attributes.


class ComponentExpert extends HTMLElement {
    constructor() {
        super(); // Chamar o construtor da classe pai (HTMLElement)
        this.shadowDom = this.attachShadow({ mode: "open" });
        this.shadowDom.appendChild(this.build());
        this.shadowDom.appendChild(this.styles());
    }

    build() {
        function createCustomElement(elementType, classNames = [], attributes = {}, content = '') {
            const element = document.createElement(elementType);

            // Adicione classes CSS
            if (classNames.length > 0) {
                element.classList.add(...classNames);
            }

            // Adicione atributos
            for (const [key, value] of Object.entries(attributes)) {
                element.setAttribute(key, value);
            }

            // Adicione conteúdo
            if (content !== '') {
                element.textContent = content;
            } else {
                element.textContent = 'Conteúdo do elemento ' + elementType;

            }

            return element;
        }

        // Exemplo de uso:
        const componentRoot = createCustomElement('div', ['root', 'main'], {
            id: 'main',
            'data-custom': 'root',
        });

        const childElement = createCustomElement('div', ['child'], {
            id: 'childDiv',
            'data-custom': 'child',
        });

        componentRoot.appendChild(childElement);

        const titleElement = createCustomElement('h1', ['title', 'child'], {
            title: 'Título do elemento',
            id: 'title',
            'data-custom': 'title',
        }, 'Título');

        childElement.appendChild(titleElement);

        return componentRoot;
    }

    styles() {
        const style = document.createElement("style");
        style.textContent = `
            .root {
                width: 100%;
                display: flex;
                justify-content: center;
                color: #333333;

                background-color: #dedede;
            }

            .child {
                width: 50%;
                display: flex;
                justify-content: flex-start;
                aling-itens: center;

                background-color: #d78795;

            }

            .child .title {
                color: #dedede;

            }
        `;

        return style;
    }
}

customElements.define("component-card", ComponentExpert);

Enter fullscreen mode Exit fullscreen mode

Quanto mais você deixar dinâmico seu componente e seus elementos mais ele vai ser flexível a diversas situações, um componente pode ser aplicado a uma navbar, um widget de notícia, um header, há várias opções!

Quando fazer um componente?

Para saber se deve ou não construir um componente em algo é preciso pensar na funcionalidade daquilo, vai se repetir várias vezes? Vai ter que aparecer com opções diferentes em outra página? É analisar o qual móvel é esse item e se ele irá ser reutilizável ou não.

Top comments (0)