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
- Ouvir eventos (
click) comaddEventListener. - Entender que o evento sobe na árvore (bubbling).
- Criar elementos no DOM.
- Ler JSON local com
fetch(precisa de servidor em127.0.0.1). - Conferir a galeria e usar o console quando falhar.
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.

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
- Por que o
fetchdeacervo.jsonpede127.0.0.1neste exercício? - O clique num botão dentro do
mainchega aodocument? Como se chama isso? - Você troca o
altgerado para string vazia. O que quebra para quem não vê a imagem?
Respostas comentadas
- 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. - Sim, o evento sobe. Isso é bubbling.
- O leitor de tela não descreve a capa.
altvazio 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.";
});