Conjunto de Questões
Agrupa múltiplas questões de tipos diferentes em uma única atividade. Permite avaliação abrangente de um tema com variação de formatos.
Experimente
Responda as questões a seguir sobre design instrucional:
1 / 3Qual sigla representa as etapas Análise, Design, Desenvolvimento, Implementação e Avaliação?
Código-fonte
Dados de exemplo
Duas perguntas de tipos diferentes, fixas no próprio arquivo.
| 1 |
<?php
|
| 2 |
$perguntas = [
|
| 3 |
[
|
| 4 |
'tipo' => 'multipla-escolha',
|
| 5 |
'pergunta' => 'Qual sigla representa as etapas Análise, Design, Desenvolvimento, Implementação e Avaliação?',
|
| 6 |
'opcoes' => [
|
| 7 |
['texto' => 'SAM', 'correta' => false],
|
| 8 |
['texto' => 'ADDIE', 'correta' => true],
|
| 9 |
['texto' => 'SCORM', 'correta' => false],
|
| 10 |
],
|
| 11 |
],
|
| 12 |
[
|
| 13 |
'tipo' => 'verdadeiro-falso',
|
| 14 |
'afirmacao' => 'A avaliação formativa ocorre somente ao final do curso.',
|
| 15 |
'correta' => false,
|
| 16 |
],
|
| 17 |
];
|
| 18 |
$total = count($perguntas);
|
| 19 |
?>
|
Estrutura da atividade
Contador no topo e as perguntas empilhadas, todas menos a primeira nascem ocultas.
| 1 |
<div class="questao" data-tipo="conjunto-questoes" data-total="<?= $total ?>">
|
| 2 |
|
| 3 |
<div class="questao-cabecalho">
|
| 4 |
<p>Responda as perguntas a seguir:</p>
|
| 5 |
<span><span class="questao-atual">1</span> / <?= $total ?></span>
|
| 6 |
</div>
|
| 7 |
|
| 8 |
<?php foreach ($perguntas as $qi => $p): ?>
|
| 9 |
<div class="questao-item<?= $qi > 0 ? ' oculto' : '' ?>" data-qi="<?= $qi ?>">
|
| 10 |
|
| 11 |
<?php if ($p['tipo'] === 'multipla-escolha'): ?>
|
| 12 |
<div class="sub-questao" data-qi="<?= $qi ?>">
|
| 13 |
<p class="questao-pergunta"><?= htmlspecialchars($p['pergunta']) ?></p>
|
| 14 |
<div class="questao-opcoes">
|
| 15 |
<?php foreach ($p['opcoes'] as $opcao): ?>
|
| 16 |
<button type="button" class="sub-opcao" data-correta="<?= $opcao['correta'] ? 'true' : 'false' ?>" data-selecionada="false" data-estado="padrao">
|
| 17 |
<?= htmlspecialchars($opcao['texto']) ?>
|
| 18 |
</button>
|
| 19 |
<?php endforeach; ?>
|
| 20 |
</div>
|
| 21 |
<button type="button" class="sub-verificar">Verificar resposta</button>
|
| 22 |
<p class="sub-feedback" hidden></p>
|
| 23 |
</div>
|
| 24 |
|
| 25 |
<?php elseif ($p['tipo'] === 'verdadeiro-falso'): ?>
|
| 26 |
<div class="sub-questao" data-qi="<?= $qi ?>">
|
| 27 |
<p class="questao-pergunta"><?= htmlspecialchars($p['afirmacao']) ?></p>
|
| 28 |
<div class="questao-opcoes">
|
| 29 |
<button type="button" class="sub-opcao" data-correta="<?= $p['correta'] ? 'true' : 'false' ?>" data-selecionada="false" data-estado="padrao">Verdadeiro</button>
|
| 30 |
<button type="button" class="sub-opcao" data-correta="<?= !$p['correta'] ? 'true' : 'false' ?>" data-selecionada="false" data-estado="padrao">Falso</button>
|
| 31 |
</div>
|
| 32 |
<button type="button" class="sub-verificar">Verificar resposta</button>
|
| 33 |
<p class="sub-feedback" hidden></p>
|
| 34 |
</div>
|
| 35 |
<?php endif; ?>
|
| 36 |
|
| 37 |
</div>
|
| 38 |
<?php endforeach; ?>
|
Botão único de avançar
Fora do laço de perguntas — sempre a última coisa do card, some de novo a cada clique.
| 1 |
<button type="button" class="questao-proximo" hidden>Próxima →</button>
|
| 2 |
|
| 3 |
<div class="questao-resultado" hidden>
|
| 4 |
<p class="questao-placar"><span class="questao-acertos">0</span> / <?= $total ?> respostas corretas</p>
|
| 5 |
<button type="button" class="questao-reiniciar">Recomeçar atividade</button>
|
| 6 |
</div>
|
| 7 |
|
| 8 |
</div>
|
Card e cabeçalho
Contêiner da atividade e a linha com instrução + contador "1 / N".
| 1 |
.questao[data-tipo="conjunto-questoes"] {
|
| 2 |
max-width: 420px;
|
| 3 |
padding: 24px;
|
| 4 |
border: 1px solid #e2e8f0;
|
| 5 |
border-radius: 16px;
|
| 6 |
background: #fff;
|
| 7 |
font-family: sans-serif;
|
| 8 |
}
|
| 9 |
|
| 10 |
.questao-cabecalho {
|
| 11 |
display: flex;
|
| 12 |
align-items: center;
|
| 13 |
justify-content: space-between;
|
| 14 |
margin-bottom: 20px;
|
| 15 |
font-size: 14px;
|
| 16 |
color: #64748b;
|
| 17 |
}
|
| 18 |
|
| 19 |
.questao-cabecalho span:last-child {
|
| 20 |
padding: 4px 10px;
|
| 21 |
border-radius: 999px;
|
| 22 |
background: #f1f5f9;
|
| 23 |
font-size: 12px;
|
| 24 |
}
|
Pergunta ativa
.oculto tira a pergunta da tela — só uma fica visível por vez.
| 1 |
.questao-item.oculto {
|
| 2 |
display: none;
|
| 3 |
}
|
| 4 |
|
| 5 |
.questao-pergunta {
|
| 6 |
margin: 0 0 16px;
|
| 7 |
font-weight: 600;
|
| 8 |
color: #0f172a;
|
| 9 |
}
|
Alternativas
Cor por data-estado, não por classe fixa — o JS só troca o atributo.
| 1 |
.questao-opcoes {
|
| 2 |
display: flex;
|
| 3 |
flex-direction: column;
|
| 4 |
gap: 8px;
|
| 5 |
margin-bottom: 16px;
|
| 6 |
}
|
| 7 |
|
| 8 |
.sub-opcao {
|
| 9 |
padding: 12px 16px;
|
| 10 |
border: 1px solid #cbd5e1;
|
| 11 |
border-radius: 10px;
|
| 12 |
background: #f8fafc;
|
| 13 |
text-align: left;
|
| 14 |
font: inherit;
|
| 15 |
cursor: pointer;
|
| 16 |
}
|
| 17 |
|
| 18 |
.sub-opcao:disabled { cursor: not-allowed; }
|
| 19 |
|
| 20 |
.sub-opcao[data-estado="selecionada"] {
|
| 21 |
border-color: #6366f1;
|
| 22 |
background: rgba(99, 102, 241, .1);
|
| 23 |
color: #4338ca;
|
| 24 |
}
|
| 25 |
|
| 26 |
.sub-opcao[data-estado="correta"] {
|
| 27 |
border-color: #16a34a;
|
| 28 |
background: rgba(22, 163, 74, .1);
|
| 29 |
color: #15803d;
|
| 30 |
}
|
| 31 |
|
| 32 |
.sub-opcao[data-estado="errada"] {
|
| 33 |
border-color: #dc2626;
|
| 34 |
background: rgba(220, 38, 38, .1);
|
| 35 |
color: #b91c1c;
|
| 36 |
}
|
Verificar e feedback
O texto de acerto/erro nasce oculto; o botão de verificar some depois de usado.
| 1 |
.sub-verificar,
|
| 2 |
.questao-proximo,
|
| 3 |
.questao-reiniciar {
|
| 4 |
width: 100%;
|
| 5 |
padding: 12px 16px;
|
| 6 |
border: none;
|
| 7 |
border-radius: 10px;
|
| 8 |
background: #4f46e5;
|
| 9 |
color: #fff;
|
| 10 |
font: inherit;
|
| 11 |
font-weight: 600;
|
| 12 |
cursor: pointer;
|
| 13 |
}
|
| 14 |
|
| 15 |
.sub-feedback {
|
| 16 |
margin-top: 12px;
|
| 17 |
padding: 10px 14px;
|
| 18 |
border-radius: 10px;
|
| 19 |
font-size: 14px;
|
| 20 |
}
|
| 21 |
|
| 22 |
.sub-feedback.acerto { background: #dcfce7; color: #14532d; }
|
| 23 |
.sub-feedback.erro { background: #fee2e2; color: #7f1d1d; }
|
| 24 |
.sub-feedback.aviso { background: #fef3c7; color: #78350f; }
|
Resultado final
Placar e botão de recomeçar, escondidos até a última pergunta ser verificada.
| 1 |
.questao-resultado {
|
| 2 |
padding: 16px;
|
| 3 |
border-radius: 10px;
|
| 4 |
background: #eef2ff;
|
| 5 |
text-align: center;
|
| 6 |
}
|
| 7 |
|
| 8 |
.questao-placar {
|
| 9 |
margin: 0 0 12px;
|
| 10 |
font-size: 22px;
|
| 11 |
font-weight: 700;
|
| 12 |
color: #4338ca;
|
| 13 |
}
|
| 14 |
|
| 15 |
.questao-reiniciar {
|
| 16 |
background: #e5e7eb;
|
| 17 |
color: #1f2937;
|
| 18 |
}
|
Encontrar os elementos da atividade
Contador, placar e o botão único de avançar — compartilhados por todas as perguntas.
| 1 |
document.addEventListener('DOMContentLoaded', function () {
|
| 2 |
document.querySelectorAll('.questao[data-tipo="conjunto-questoes"]').forEach(function (questao) {
|
| 3 |
var total = parseInt(questao.dataset.total, 10);
|
| 4 |
var acertos = 0;
|
| 5 |
var atualEl = questao.querySelector('.questao-atual');
|
| 6 |
var proximo = questao.querySelector('.questao-proximo');
|
| 7 |
var resultado = questao.querySelector('.questao-resultado');
|
| 8 |
var acertosEl = questao.querySelector('.questao-acertos');
|
Selecionar e verificar cada pergunta
Um bloco de correção por pergunta — cada uma guarda se já foi respondida.
| 1 |
questao.querySelectorAll('.sub-questao').forEach(function (subQuestao) {
|
| 2 |
var qi = parseInt(subQuestao.dataset.qi, 10);
|
| 3 |
var opcoes = subQuestao.querySelectorAll('.sub-opcao');
|
| 4 |
var verificar = subQuestao.querySelector('.sub-verificar');
|
| 5 |
var fb = subQuestao.querySelector('.sub-feedback');
|
| 6 |
|
| 7 |
// Seleção tipo rádio: marca a escolhida, devolve as demais ao padrão.
|
| 8 |
// Nada é corrigido ainda — só "Verificar" revela acerto ou erro.
|
| 9 |
opcoes.forEach(function (opcao) {
|
| 10 |
opcao.addEventListener('click', function () {
|
| 11 |
if (subQuestao.dataset.respondida === 'true') return;
|
| 12 |
opcoes.forEach(function (o) {
|
| 13 |
var sel = o === opcao;
|
| 14 |
o.dataset.selecionada = sel ? 'true' : 'false';
|
| 15 |
o.dataset.estado = sel ? 'selecionada' : 'padrao';
|
| 16 |
});
|
| 17 |
fb.hidden = true;
|
| 18 |
});
|
| 19 |
});
|
| 20 |
|
| 21 |
verificar.addEventListener('click', function () {
|
| 22 |
if (subQuestao.dataset.respondida === 'true') return;
|
| 23 |
|
| 24 |
var escolhida = Array.prototype.filter.call(opcoes, function (o) {
|
| 25 |
return o.dataset.selecionada === 'true';
|
| 26 |
})[0];
|
| 27 |
if (!escolhida) {
|
| 28 |
fb.className = 'sub-feedback aviso';
|
| 29 |
fb.textContent = 'Escolha uma alternativa antes de verificar.';
|
| 30 |
fb.hidden = false;
|
| 31 |
return;
|
| 32 |
}
|
| 33 |
|
| 34 |
subQuestao.dataset.respondida = 'true';
|
| 35 |
var correta = escolhida.dataset.correta === 'true';
|
| 36 |
if (correta) acertos++;
|
| 37 |
|
| 38 |
opcoes.forEach(function (o) {
|
| 39 |
o.disabled = true;
|
| 40 |
if (o.dataset.correta === 'true') o.dataset.estado = 'correta';
|
| 41 |
else if (o === escolhida) o.dataset.estado = 'errada';
|
| 42 |
else o.dataset.estado = 'padrao';
|
| 43 |
});
|
| 44 |
|
| 45 |
fb.className = 'sub-feedback ' + (correta ? 'acerto' : 'erro');
|
| 46 |
fb.textContent = correta ? 'Correto!' : 'Não foi dessa vez.';
|
| 47 |
fb.hidden = false;
|
| 48 |
|
| 49 |
verificar.hidden = true;
|
Revelar o botão de avançar
Rotula pra esta pergunta ("Próxima →" ou "Ver resultado" na última) e grava o qi nele.
| 1 |
proximo.textContent = qi < total - 1 ? 'Próxima →' : 'Ver resultado';
|
| 2 |
proximo.dataset.qi = qi;
|
| 3 |
proximo.hidden = false;
|
| 4 |
});
|
| 5 |
});
|
Avançar pra próxima pergunta ou pro resultado
Um único botão pra atividade inteira — o clique já o esconde de novo.
| 1 |
proximo.addEventListener('click', function () {
|
| 2 |
var qi = parseInt(proximo.dataset.qi, 10);
|
| 3 |
proximo.hidden = true;
|
| 4 |
questao.querySelector('.questao-item[data-qi="' + qi + '"]').classList.add('oculto');
|
| 5 |
|
| 6 |
if (qi === total - 1) {
|
| 7 |
resultado.hidden = false;
|
| 8 |
acertosEl.textContent = acertos;
|
| 9 |
} else {
|
| 10 |
questao.querySelector('.questao-item[data-qi="' + (qi + 1) + '"]').classList.remove('oculto');
|
| 11 |
atualEl.textContent = qi + 2;
|
| 12 |
}
|
| 13 |
});
|
Reiniciar
Zera o placar, volta pra primeira pergunta e limpa seleção, cores e feedback de todas.
| 1 |
questao.querySelector('.questao-reiniciar').addEventListener('click', function () {
|
| 2 |
acertos = 0;
|
| 3 |
atualEl.textContent = 1;
|
| 4 |
resultado.hidden = true;
|
| 5 |
|
| 6 |
questao.querySelectorAll('.questao-item').forEach(function (item, i) {
|
| 7 |
item.classList.toggle('oculto', i !== 0);
|
| 8 |
});
|
| 9 |
questao.querySelectorAll('.sub-questao').forEach(function (subQuestao) {
|
| 10 |
delete subQuestao.dataset.respondida;
|
| 11 |
subQuestao.querySelector('.sub-verificar').hidden = false;
|
| 12 |
subQuestao.querySelector('.sub-feedback').hidden = true;
|
| 13 |
});
|
| 14 |
questao.querySelectorAll('.sub-opcao').forEach(function (o) {
|
| 15 |
o.disabled = false;
|
| 16 |
o.dataset.selecionada = 'false';
|
| 17 |
o.dataset.estado = 'padrao';
|
| 18 |
});
|
| 19 |
});
|