Programação II – ECO Aulas DOM & Eventos

Manipulação do DOM: querySelector, eventos e innerHTML

Vamos aprender a selecionar elementos na página, reagir a eventos do usuário e atualizar o conteúdo HTML dinamicamente com JavaScript.

Introdução

Quando escrevemos JavaScript para o navegador, nosso “campo de trabalho” é o DOM (Document Object Model): uma representação em árvore do HTML da página.

Manipular o DOM significa selecionar elementos, ler e alterar conteúdo, estilos e atributos, além de reagir a interações do usuário (cliques, teclas, envio de formulário, etc.).

Ilustração da árvore DOM

O DOM (Document Object Model) representa a página HTML como uma árvore de nós, em que cada elemento e cada texto viram objetos conectados hierarquicamente.

Exemplo de código HTML

<!DOCTYPE html>
        <html>
          <head>
            <title>Página exemplo</title>
          </head>
          <body>
            <h1>Olá, DOM!</h1>
            <p>Um parágrafo de teste.</p>
          </body>
        </html>
        

Representação da árvore DOM

A estrutura acima é convertida pelo navegador em uma árvore de nós, começando em Document, com o elemento html como raiz do documento.

Document
        └── html
            ├── head
            │   └── title
            │       └── "Página exemplo"
            └── body
                ├── h1
                │   └── "Olá, DOM!"
                └── p
                    └── "Um parágrafo de teste."
        

Cada elemento da marcação (html, head, body, h1, p, title) é um nó do tipo Element, e os textos entre as tags são nós do tipo Text na árvore DOM.

Vamos focar em três ideias fundamentais: querySelector para selecionar, eventos para reagir e innerHTML para atualizar o conteúdo.

1. DOM e querySelector

Com JavaScript, podemos acessar esses objetos pelo objeto global document e alterar a página sem recarregar.

1.1 Selecionando elementos com querySelector

document.querySelector(seletor) retorna o primeiro elemento que combina com o seletor CSS informado.

O seletor é exatamente o mesmo que você usaria no CSS: #id, .classe, tag, combinações, etc.

// Seleciona o primeiro parágrafo da página
const primeiroParagrafo = document.querySelector("p");

// Seleciona o elemento com id "titulo"
const titulo = document.querySelector("#titulo");

// Seleciona o primeiro elemento com a classe "destaque"
const destaque = document.querySelector(".destaque");
Resumo: use # para id, . para classe e o nome da tag para elementos simples.

1.2 Selecionando vários elementos com querySelectorAll

Enquanto document.querySelector() devolve apenas o primeiro elemento que combina com o seletor, document.querySelectorAll() retorna todos os elementos que combinam, em uma lista (NodeList).

// Seleciona todos os parágrafos da página
    const paragrafos = document.querySelectorAll("p");
    
    // Acessa o 3º parágrafo (índice 2)
    const terceiroParagrafo = paragrafos[2];
    
    // Altera o texto do 3º parágrafo
    terceiroParagrafo.textContent = "Sou o terceiro parágrafo!";
    

Lembre que os índices começam em 0: o primeiro parágrafo é [0], o segundo é [1], o terceiro é [2] e assim por diante.

1.2.1 Exemplo: quarta ocorrência de uma classe

Também podemos buscar várias ocorrências de uma mesma classe e acessar uma posição específica da lista, como a 4ª ocorrência de elementos com a classe .destaque.

// Seleciona todos os elementos com a classe "destaque"
    const destaques = document.querySelectorAll(".destaque");
    
    // Pega a 4ª ocorrência (índice 3)
    const quartoDestaque = destaques[3];
    
    // Adiciona uma borda para visualizar
    quartoDestaque.style.border = "2px solid red";
    

1.2.2Combinação com seletores de CSS

Podemos combinar querySelectorAll com seletores de CSS, por exemplo, para pegar o 3º parágrafo dentro de um container específico:

// Seleciona o container com id "conteudo"
    const conteudo = document.querySelector("#conteudo");
    
    // Dentro do container, pega todos os parágrafos
    const paragrafosConteudo = conteudo.querySelectorAll("p");
    
    // 3º parágrafo desse container
    const terceiroNoConteudo = paragrafosConteudo[2];
    

Resumo: use querySelector() quando quiser apenas um elemento e querySelectorAll() quando precisar de uma lista para acessar posições específicas (3º, 4º etc.).

1.3 querySelector dentro de outro elemento

Também podemos chamar querySelector em um elemento, não só em document, para procurar dentro dele.

// Seleciona a seção principal
const secao = document.querySelector("section");

// Dentro da seção, seleciona o primeiro <h2>
const subtitulo = secao.querySelector("h2");

1.4 Preview rápido: selecionando e destacando um elemento

Veja o exemplo abaixo: vamos buscar um parágrafo pelo id e mudar o estilo dele via JavaScript.

Preview – Seleção com querySelector

Este parágrafo será destacado ao clicar no botão.

<p id="paragrafo-destaque">Este parágrafo será destacado...</p>
<button id="btn-destacar">Destacar parágrafo</button>

<script>
  const paragrafo = document.querySelector("#paragrafo-destaque");
  const botao = document.querySelector("#btn-destacar");

  botao.addEventListener("click", () => {
    paragrafo.style.backgroundColor = "#fff3e0";
    paragrafo.style.borderLeft = "4px solid #ff9800";
  });
</script>

2. Eventos: reagindo a cliques e teclas

2.1 O que é um evento?

Um evento é qualquer coisa que acontece na página: clique, movimento do mouse, tecla pressionada, envio de formulário, carregamento da página, etc.

Podemos “escutar” esses eventos e executar uma função quando eles acontecem, deixando a página interativa.

2.2 addEventListener

A forma mais usada é elemento.addEventListener(tipo, funcao), onde tipo pode ser "click", "keyup", "submit" e muitos outros.

const botao = document.querySelector("#botao");

botao.addEventListener("click", function () {
  console.log("Botão foi clicado!");
});

2.3 Exemplo: contador com clique

No exemplo abaixo, cada clique no botão incrementa um número exibido na tela.

Preview – Contador com evento de clique

Cliques: 0

<p>Cliques: <span id="contador-cliques">0</span></p>
<button id="btn-contar">Clique aqui</button>

<script>
  const spanContador = document.querySelector("#contador-cliques");
  const btnContar = document.querySelector("#btn-contar");
  let totalCliques = 0;

  btnContar.addEventListener("click", () => {
    totalCliques++;
    spanContador.textContent = totalCliques;
  });
</script>

2.4 Evento de teclado (keyup)

Podemos ouvir eventos no document inteiro, por exemplo para contar quantas teclas o usuário digitou.

let teclasDigitadas = 0;
const saida = document.querySelector("#saida-teclas");
const campoTeclas = document.querySelector("#campo-teclas");

// Aqui nós registramos um "ouvinte de eventos" no documento inteiro.
// "keyup" é disparado sempre que uma tecla é SOLTA.
// A função (evento) => { ... } será executada a cada vez que isso acontecer.
//campoTeclas.addEventListener("keyup", (evento) => { conta apenas no campo
        
document.addEventListener("keyup", (evento) => {
  teclasDigitadas++;
  saida.textContent = "Teclas digitadas: " + teclasDigitadas;
});
Preview – Contando teclas digitadas (keyup)

Digite qualquer coisa no campo abaixo e observe o contador:

Teclas digitadas: 0

3. innerHTML na prática

3.1 O que é innerHTML?

innerHTML é uma propriedade que representa o conteúdo HTML interno de um elemento.

Podemos ler esse conteúdo ou sobrescrevê-lo com uma nova string contendo HTML.

const caixa = document.querySelector("#caixa");

// Lendo o HTML interno
console.log(caixa.innerHTML);

// Substituindo o conteúdo
caixa.innerHTML = "<strong>Novo conteúdo</strong> gerado via JS!";
Se você só precisa trocar texto simples, prefira textContent. Use innerHTML quando realmente quiser inserir tags HTML (por exemplo, <strong>, <li>, <em>, etc.).

3.2 Exemplo: mensagem dinâmica

No exemplo abaixo, ao clicar no botão trocamos o conteúdo de uma <div> usando innerHTML.

Preview – innerHTML para atualizar mensagem
Clique no botão para alterar esta mensagem.
<div id="mensagem-dom">
  Clique no botão para alterar esta mensagem.
</div>
<button id="btn-mudar-mensagem">Mudar mensagem</button>

<script>
  const mensagem = document.querySelector("#mensagem-dom");
  const btnMensagem = document.querySelector("#btn-mudar-mensagem");

  btnMensagem.addEventListener("click", () => {
    mensagem.innerHTML = "Mensagem <strong>atualizada</strong> com (...)";
  });
</script>

3.3 Montando uma lista com innerHTML

Também podemos construir um HTML inteiro em uma string e atribuir de uma vez para montar uma lista dinamicamente.

const frutas = ["Maçã", "Banana", "Laranja"];
const lista = document.querySelector("#lista-frutas");

let html = "";
for (const fruta of frutas) {
  html += "<li>" + fruta + "</li>";
}

lista.innerHTML = html;
Em aplicações maiores, é comum preferir document.createElement e appendChild para manipular nós de forma mais controlada, mas innerHTML é ótimo para exemplos simples e protótipos.

4. Mini-projeto: lista de tarefas com DOM

Agora vamos juntar querySelector, eventos e innerHTML em um mini “gerenciador” de tarefas simples.

4.1 Comportamento desejado

  • O usuário digita uma tarefa em um input.
  • Clica em “Adicionar” ou aperta Enter.
  • A tarefa aparece em uma lista abaixo.
  • Se o campo estiver vazio, exibimos uma mensagem de erro.
Preview – Lista de tarefas com DOM

    4.2 Código HTML + JavaScript completo

    Ver HTML básico da página
    <body>
      <h1>Lista de tarefas</h1>
    
      <label for="tarefa-input">Nova tarefa</label>
      <input type="text" id="tarefa-input" placeholder="Ex: Estudar DOM">
      <button id="btn-adicionar-tarefa">Adicionar tarefa</button>
    
      <p id="erro-tarefa"></p>
      <ul id="lista-tarefas"></ul>
    
      <script src="tarefas.js"></script>
    </body>
    Ver JavaScript comentado (tarefas.js)
    // 1. Selecionar elementos da página
    const inputTarefa = document.querySelector("#tarefa-input");
    const btnAdicionar = document.querySelector("#btn-adicionar-tarefa");
    const listaTarefas = document.querySelector("#lista-tarefas");
    const pErro = document.querySelector("#erro-tarefa");
    
    // 2. Array para guardar as tarefas (estado da aplicação)
    const tarefas = [];
    
    // 3. Função para redesenhar a lista usando innerHTML
    function atualizarLista() {
      let html = "";
    
      for (const tarefa of tarefas) {
        html += "<li>" + tarefa + "</li>";
      }
    
      listaTarefas.innerHTML = html;
    }
    
    // 4. Função para adicionar uma nova tarefa
    function adicionarTarefa() {
      const texto = inputTarefa.value.trim();
    
      if (texto === "") {
        pErro.textContent = "Digite uma tarefa antes de adicionar.";
        return;
      }
    
      pErro.textContent = ""; // limpa mensagem de erro
      tarefas.push(texto);
      inputTarefa.value = "";
      atualizarLista();
    }
    
    // 5. Conectar eventos
    btnAdicionar.addEventListener("click", adicionarTarefa);
    
    // Permite adicionar com Enter
    inputTarefa.addEventListener("keyup", (evento) => {
      if (evento.key === "Enter") {
        adicionarTarefa();
      }
    });
    Para testar em um arquivo separado, crie um index.html simples e um tarefas.js com o código acima, da mesma forma que você já fez nas aulas anteriores.

    Para memorizar!

    1 – Alterando o tema da página

    Crie dois botões: “Tema claro” e “Tema escuro”. Ao clicar em cada um, altere o backgroundColor do body e a cor do texto usando querySelector e eventos.

    • Use document.querySelector("body") para pegar o body.
    • No evento de clique dos botões, altere style.backgroundColor e style.color.

    2 – Lista de compras

    Baseando-se na lista de tarefas, crie uma lista de compras que mostre a quantidade de itens abaixo da lista.

    • Use um <span> para exibir o total de itens.
    • Atualize o texto do span sempre que adicionar um item, com textContent.

    3 – Perguntas e respostas

    Monte uma página com três perguntas de revisão. Ao clicar em um botão “Mostrar resposta”, mostre a resposta usando innerHTML em uma <div> escondida.

    • Comece com a <div> vazia.
    • No clique, use div.innerHTML = "Resposta: ...".

    Roteiro de estudo para quem faltou

    • Revise a ideia de DOM e como o navegador transforma HTML em uma árvore de elementos.
    • Pratique querySelector e addEventListener com pequenos exemplos (botões, parágrafos, inputs).
    • Experimente trocar innerHTML e textContent e observe a diferença.
    • Implemente o mini-projeto da lista de tarefas e uma das atividades propostas.