Pular para o conteúdo
murad.guide

Referência Essencial da Web

Capítulo 15

Eventos, DOM e JSON

4 min de leitura 733 palavras 1 gravura

Trabalhe numa cópia da pasta inicio/ desta etapa. Ela já abre ou executa com as instruções do README. Leia o código, mude uma coisa e anote sua previsão antes de recarregar. Compare com a referência na pasta da etapa. Se nada mudar, confira a extensão do arquivo, o arquivo salvo e o caminho aberto. Blocos adicionais do capítulo são experiências separadas; a pasta de referência contém o programa completo desta etapa.

A Biblioteca da Ribeira é um acervo comunitário fictício no bairro da Ribeira, Recife. Neste capítulo a galeria do acervo nasce de um arquivo acervo.json. O navegador pede o JSON, monta cartões e mostra capas.

O exemplo está em pacote de exemplos/15-eventos-dom-e-json/. Não abra só pelo disco se quiser ver o fetch. Sirva a pasta em 127.0.0.1.

Ciclo: ler → copiar → mudar uma coisa → prever → recarregar → conferir.

O que você vai aprender

Eventos

Evento é algo que acontece na página: clique, tecla, envio. Você registra uma função. Quando o evento ocorre, a função roda.

document.getElementById("gerar").addEventListener("click", function () {
  console.log("clicou");
});

Não coloque onclick no HTML neste volume. O ouvinte fica no arquivo .js. Assim o HTML descreve a página e o script descreve a reação.

type="button" no botão evita que um form recarregue a página e “apague” o que o script fez.

Bubbling

O clique no botão também acontece no main, no body, no document. O evento sobe. Isso se chama bubbling.

Você pode ouvir o clique na lista inteira e descobrir qual item foi o alvo (evento.target). Não precisa um ouvinte por cartão.

Se um botão dentro de um cartão não deve acionar o cartão, o código do botão pode chamar evento.stopPropagation(). No exemplo da galeria não precisamos disso: só montamos cartões.

Erro comum: dois ouvintes no mesmo clique (no filho e no pai) e achar que é bug. É a subida do evento. O console.log nos dois mostra a ordem.

O DOM

DOM é a árvore da página na memória do navegador. document é a raiz. header, main e footer são ramos.

Árvore do DOM: document no topo, depois header, main e footer

const artigo = document.createElement("article");
artigo.className = "cartao";
caixa.appendChild(artigo);

createElement cria. appendChild encaixa. querySelector acha um descendente. textContent escreve texto seguro.

Não monte o título do livro com innerHTML se o dado veio de um arquivo que você não controla no futuro. Neste exercício o JSON é nosso. Ainda assim o exemplo preenche título e autoria com textContent.

JSON e fetch em 127.0.0.1

JSON é texto com cara de objeto: chaves entre aspas, colchetes na lista.

acervo.json na pasta do exemplo:

[
  {"titulo": "Maré Alta", "autoria": "Iara Campos", "capa": "ribeira-fachada.png"},
  {"titulo": "Caderno do Cais", "autoria": "Lina Bezerra", "capa": "logo-ribeira.png"},
  {"titulo": "O Telhado de Palha", "autoria": "Nuno Freire", "capa": "ribeira-fachada.png"}
]

fetch("acervo.json") pede esse arquivo. No endereço file:// o navegador bloqueia. Por isso:

python -m http.server 8080 --bind 127.0.0.1

Na pasta curso, abra http://127.0.0.1:8080/exemplos/15-eventos-dom-e-json/. Só a sua máquina. Não é publicação.

Mude uma coisa. Abra index.html com dois cliques (disco). Preveja a mensagem de falha na galeria. Depois sirva em 127.0.0.1 e recarregue. As capas devem aparecer.

A galeria completa

galeria.js:

const caixa = document.getElementById("galeria");
fetch("acervo.json")
  .then(function (resposta) { return resposta.json(); })
  .then(function (livros) {
    livros.forEach(function (livro) {
      const artigo = document.createElement("article");
      artigo.className = "cartao";
      artigo.innerHTML = "<h2></h2><p></p><img alt=\"\">";
      artigo.querySelector("h2").textContent = livro.titulo;
      artigo.querySelector("p").textContent = livro.autoria;
      const img = artigo.querySelector("img");
      img.src = livro.capa;
      img.alt = "Capa ilustrativa de " + livro.titulo;
      caixa.appendChild(artigo);
    });
  })
  .catch(function () {
    caixa.textContent = "Não deu para ler o JSON. Sirva a pasta em 127.0.0.1.";
  });

.then espera a resposta. .catch cobre falha de rede ou JSON inválido. O alt descreve a capa.

Debug e os três lugares

Console: aba Rede (Network). Recarregue. A linha acervo.json deve ser 200. Se for vermelha, o caminho está errado ou você está no disco.

Disco = arquivos. 127.0.0.1 = teste local com fetch. Publicação pública = outro passo, fora deste capítulo. Não publique o acervo fictício como se fosse de uma biblioteca real.

Vírgula a mais no JSON quebra o parse. O console mostra Unexpected token. Valide as aspas.

Atividades

  1. Por que o fetch de acervo.json pede 127.0.0.1 neste exercício?
  2. O clique num botão dentro do main chega ao document? Como se chama isso?
  3. Você troca o alt gerado para string vazia. O que quebra para quem não vê a imagem?

Respostas comentadas

  1. Porque o navegador trata file:// como origem que não pode ler o JSON ao lado. O servidor local entrega os dois arquivos pela mesma origem.
  2. Sim, o evento sobe. Isso é bubbling.
  3. O leitor de tela não descreve a capa. alt vazio só vale para imagem decorativa. Aqui a capa informa o título.

O arquivo completo

Referência do exemplo 15-eventos-dom-e-json, reproduzida aqui para que você possa conferir sem sair da página.

galeria.js

const caixa = document.getElementById("galeria");
fetch("acervo.json")
  .then(function (resposta) { if (!resposta.ok) throw new Error("HTTP " + resposta.status); return resposta.json(); })
  .then(function (livros) {
    if (!Array.isArray(livros)) throw new Error("Formato inesperado");
    if (!livros.length) caixa.textContent = "Nenhum livro nesta lista.";
    livros.forEach(function (livro) {
      const artigo = document.createElement("article");
      artigo.className = "cartao";
      artigo.innerHTML = "<h2></h2><p></p><img alt=\"\">";
      artigo.querySelector("h2").textContent = livro.titulo;
      artigo.querySelector("p").textContent = livro.autoria;
      const img = artigo.querySelector("img");
      img.src = livro.capa;
      img.alt = "Capa ilustrativa de " + livro.titulo;
      caixa.appendChild(artigo);
    });
  })
  .catch(function () {
    caixa.textContent = "Não deu para ler o JSON. Sirva a pasta em 127.0.0.1.";
  });