1 / 10
Modulo 3 / JavaScript

Projeto Pratico:
App Interativa

Aplicação completa integrando tudo que aprendemos em JavaScript.

school Aula 17 schedule 2 horas

O projeto

Quiz interativo

description O que vamos construir

  • Um quiz com perguntas vindas de uma API
  • O usuário responde clicando nas alternativas
  • Feedback visual de acerto/erro em tempo real
  • Pontuação e tela de resultado final

integration_instructions Conceitos integrados

data_object Variáveis, arrays e objetos
account_tree Manipulação do DOM
touch_app Eventos (click, submit)
cloud_download Fetch API e async/await
fork_right Estruturas de controle e funções

Passo 1

Estrutura HTML

<!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="UTF-8"> <title>Quiz JS</title> <link rel="stylesheet" href="style.css"> </head> <body> <div id="app"> <div id="inicio"> <h1>Quiz JavaScript</h1> <button id="btnIniciar"> Iniciar </button> </div> <div id="quiz" hidden> <div id="progresso"></div> <h2 id="pergunta"></h2> <div id="opcoes"></div> </div> <div id="resultado" hidden></div> </div> <script src="script.js"></script> </body> </html>

folder Estrutura de arquivos

quiz/
├── index.html
├── style.css
└── script.js

layers 3 telas do app

#inicio Tela inicial com botão "Iniciar"
#quiz Pergunta atual e alternativas
#resultado Pontuação final e botão de reiniciar

Passo 2

Buscando perguntas

// Variáveis globais let perguntas = []; let atual = 0; let pontos = 0; // Buscar perguntas da API async function buscarPerguntas() { const url = 'https://tryvia.ptr.red/api.php' + '?amount=10&type=multiple'; try { const res = await fetch(url); const data = await res.json(); perguntas = data.results; } catch (erro) { console.log('Erro:', erro); } }

public Open Trivia DB

  • API gratuita e sem autenticação
  • Retorna perguntas de múltipla escolha
  • Cada pergunta vem com a resposta correta e 3 incorretas
lightbulb O parâmetro amount=10 define quantas perguntas buscar. O type=multiple garante que todas sejam de múltipla escolha.
Formato da resposta:
{ "question": "Pergunta...", "correct_answer": "Certa", "incorrect_answers": [ "Errada 1", "Errada 2", "Errada 3" ] }

Passo 3

Montando as alternativas

// Embaralhar array function embaralhar(array) { return array .sort(() => Math.random() - 0.5); } // Montar alternativas function getAlternativas(pergunta) { const todas = [ ...pergunta.incorrect_answers, pergunta.correct_answer ]; return embaralhar(todas); }

shuffle Por que embaralhar?

  • A API sempre retorna a correta separada das incorretas
  • Se apenas adicionarmos ao final, a correta sempre será a última
  • Usamos o operador spread ... para juntar os arrays
  • O sort com Math.random() embaralha a ordem

Passo 4

Exibindo a pergunta

function exibirPergunta() { const p = perguntas[atual]; const alternativas = getAlternativas(p); // Atualizar progresso elProgresso.textContent = `${atual + 1} / ${perguntas.length}`; // Exibir pergunta elPergunta.innerHTML = p.question; // Criar botões para cada alternativa elOpcoes.innerHTML = ''; alternativas.forEach((alt) => { const btn = document .createElement('button'); btn.innerHTML = alt; btn.className = 'opcao'; elOpcoes.appendChild(btn); }); }

pattern DOM: o padrão criar e inserir

1 Limpar o container com innerHTML = ''
2 Iterar sobre as alternativas com forEach
3 Criar button para cada alternativa
4 Inserir no container com appendChild
lightbulb Usamos innerHTML para a pergunta porque a API retorna texto com entidades HTML (como &quot;).

Passo 5

Verificando a resposta

// Delegação de eventos nas opções elOpcoes.addEventListener('click', (e) => { if (!e.target.classList .contains('opcao')) return; const resposta = e.target.textContent; const correta = perguntas[atual].correct_answer; if (resposta === correta) { pontos++; e.target.classList .add('correta'); } else { e.target.classList .add('errada'); } // Avançar após 1 segundo setTimeout(() => { atual++; if (atual < perguntas.length) { exibirPergunta(); } else { exibirResultado(); } }, 1000); } );

psychology Lógica principal

  • Usamos delegação no container de opções
  • Comparamos o texto clicado com correct_answer
  • Adicionamos classe CSS para feedback visual
  • setTimeout dá tempo para ver o resultado antes de avançar
warning Desabilite os botões depois do clique para evitar respostas duplicadas (adicione uma variável respondeu como controle).

Passo 6

Tela de resultado

function exibirResultado() { // Esconder quiz, mostrar resultado elQuiz.hidden = true; elResultado.hidden = false; const total = perguntas.length; const pct = Math.round((pontos / total) * 100); let msg = 'Tente novamente!'; if (pct >= 80) msg = 'Excelente!'; else if (pct >= 60) msg = 'Bom trabalho!'; elResultado.innerHTML = ` <h2>${msg}</h2> <p>${pontos} de ${total} (${pct}%)</p> <button id="btnReiniciar"> Jogar novamente </button> `; }

visibility Controlando telas com hidden

O atributo hidden é uma forma simples de alternar entre as 3 telas:

// Mostrar uma tela elInicio.hidden = true; elQuiz.hidden = false; elResultado.hidden = true;
lightbulb Uma alternativa seria usar classList.toggle('hidden') com uma classe CSS, mas o atributo nativo é mais simples para este caso.

Indo além

Desafios extras

rocket_launch Funcionalidades adicionais

  • Timer regressivo para cada pergunta
  • Barra de progresso visual
  • Animações de transição entre perguntas
  • Selecionar categoria e dificuldade antes de iniciar
  • Salvar recorde no localStorage

palette Estilização

  • Cores de feedback: verde para acerto, vermelho para erro
  • Fontes legíveis e tamanho adequado para as perguntas
  • Hover nos botões para indicar interatividade
  • Layout responsivo para dispositivos móveis
  • Dark mode ou tema customizado
Próxima aula

Aula 18

Conceitos de versionamento. Instalação e configuração do Git.

task_alt O que aprendemos hoje

  • check_circle Planejar a estrutura de uma aplicação (HTML, CSS, JS separados)
  • check_circle Buscar dados de uma API com fetch e async/await
  • check_circle Criar elementos dinamicamente com DOM e forEach
  • check_circle Usar delegação de eventos para interatividade
  • check_circle Controlar o fluxo da aplicação com variáveis e condicionais
Próxima aula
auto_stories Referência: MDN JavaScript
Leandro Medeiros