DEV Community

Ana Luiza Pardini
Ana Luiza Pardini

Posted on

2

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.

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay