Aplicação completa integrando tudo que aprendemos em JavaScript.
<!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>
#inicio
Tela inicial com botão "Iniciar"
#quiz
Pergunta atual e alternativas
#resultado
Pontuação final e botão de reiniciar
// 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);
}
}
amount=10 define quantas perguntas buscar. O type=multiple garante que todas sejam de múltipla escolha.
{
"question": "Pergunta...",
"correct_answer": "Certa",
"incorrect_answers": [
"Errada 1",
"Errada 2",
"Errada 3"
]
}
// 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);
}
... para juntar os arrays
sort
com Math.random() embaralha a ordemfunction 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);
});
}
innerHTML = ''
forEach
button para cada alternativa
appendChild
innerHTML para a pergunta porque a API retorna texto com entidades
HTML (como ").
// 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);
}
);
correct_answer
setTimeout dá tempo para ver o resultado antes de avançarrespondeu como controle).
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>
`;
}
O atributo hidden é uma forma simples de alternar entre as 3 telas:
// Mostrar uma tela
elInicio.hidden = true;
elQuiz.hidden = false;
elResultado.hidden = true;
classList.toggle('hidden') com uma classe CSS, mas o
atributo nativo é mais simples para este caso.
localStorageConceitos de versionamento. Instalação e configuração do Git.