“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”
- Frederick Philips Brooks
Mythical Man-Month 저자
728x90
지난 게시글에서 추가한 내용이 script에 있으므로 이번에는 script 만 보여드리면서 설명하겠습니다.
script
<script>
const cbtQuiz = document.querySelector(".cbt__quiz");
const cbtOmr = document.querySelector(".cbt__omr");
const cbtSubmit = document.querySelector(".cbt__submit");
const cbtLength = document.querySelector(".cbt__length");
const cbtRest = document.querySelector(".cbt__rest");
let questionAll = []; //모든 퀴즈 정보
let questionLength = 0; //전체 문제 수
let questionRest = questionLength; //남은 문제 수
//데이터 불러오기
const dataQuestion = () => {
fetch("json/gineungsaWD2023_01.json")
.then(res => res.json())
.then(items => {
questionAll = items.map((item, index) => {
const formattedQuestion = {
question: item.question,
number: index + 1
}
const answerChoices = [...item.incorrect_answer]; //오답 불러오기
formattedQuestion.answer = Math.floor(Math.random() * answerChoices.length) + 1; //정답을 랜덤으로 불러오기
answerChoices.splice(formattedQuestion.answer - 1, 0, item.correct_answer); //정답을 랜덤으로 추가
//보기를 추가
answerChoices.forEach((choice,index) => {
formattedQuestion["choice" + (index+1)] = choice;
});
//문제에 대한 해설이 있으면 출력
if(item.hasOwnProperty("question_desc")){
formattedQuestion.question_desc = item.question_desc;
}
//문제에 대한 이미지가 있으면 출력
if(item.hasOwnProperty("question_img")){
formattedQuestion.question_img = item.question_img;
}
//해설이 있으면 출력
if(item.hasOwnProperty("desc")){
formattedQuestion.desc = item.desc;
}
return formattedQuestion;
});
newQuestion(); //문제 만들기
//전체 문제 수
questionLength = questionAll.length;
cbtLength.innerHTML = questionLength;
cbtRest.innerHTML = questionLength;
})
.catch((err) => console.log(err));
}
//문제 만들기
const newQuestion = () => {
const exam = [];
const omr = [];
questionAll.forEach((question, number) => {
exam.push(`
<div class="cbt">
<div class="cbt__question"><span>${question.number}</span>. ${question.question}</div>
<div class="cbt__question__img"></div>
<div class="cbt__selects">
<input type="radio" id="select${number}_1" name="select${number}" value="${number+1}_1" onclick="answerSelect(this)">
<label for="select${number}_1"><span>${question.choice1}</span></label>
<input type="radio" id="select${number}_2" name="select${number}" value="${number+1}_2" onclick="answerSelect(this)">
<label for="select${number}_2"><span>${question.choice2}</span></label>
<input type="radio" id="select${number}_3" name="select${number}" value="${number+1}_3" onclick="answerSelect(this)">
<label for="select${number}_3"><span>${question.choice3}</span></label>
<input type="radio" id="select${number}_4" name="select${number}" value="${number+1}_4" onclick="answerSelect(this)">
<label for="select${number}_4"><span>${question.choice4}</span></label>
</div>
<div class="cbt__desc hide">${question.desc}</div>
</div>
`);
omr.push(`
<div class="omr">
<strong>${question.number}</strong>
<input type="radio" name="omr${number}" id="omr${number}_1" value="${number}_0">
<label for="omr${number}_1"><span class="label-inner">1</span></label>
<input type="radio" name="omr${number}" id="omr${number}_2" value="${number}_1">
<label for="omr${number}_2"><span class="label-inner">2</span></label>
<input type="radio" name="omr${number}" id="omr${number}_3" value="${number}_2">
<label for="omr${number}_3"><span class="label-inner">3</span></label>
<input type="radio" name="omr${number}" id="omr${number}_4" value="${number}_3">
<label for="omr${number}_4"><span class="label-inner">4</span></label>
</div>
`);
})
cbtQuiz.innerHTML = exam.join('');
cbtOmr.innerHTML = omr.join('');
}
//정답 확인
const answerQuiz = () => {
const cbtSelects = document.querySelectorAll(".cbt__selects");
questionAll.forEach((question, number) => {
const quizSelectsWrap = cbtSelects[number];
const userSelector = `input[name=select${number}]:checked`;
const userAnswer = (quizSelectsWrap.querySelector(userSelector) || {}).value;
const numberAnswer = userAnswer ? userAnswer.slice(-1) : undefined;
if(numberAnswer == question.answer){
console.log("정답");
cbtSelects[number].parentElement.classList.add("good");
} else {
console.log("오답");
cbtSelects[number].parentElement.classList.add("bad");
//오답일 경우 정답 표시
const label = cbtSelects[number].querySelectorAll("label");
label[question.answer-1].classList.add("correct");
}
//설명 숨기기
const quizDesc = document.querySelectorAll(".cbt__desc");
if(quizDesc[number].innerHTML == "undefined"){
quizDesc[number].classList.add("hide");
} else {
quizDesc[number].classList.remove("hide");
}
});
}
//보기 체크
const answerSelect2 = (el) => {
const answer = el.value; //value="${number}_1"
const answerNum = answer.split("_");
const select = document.querySelectorAll(".cbt__omr .omr"); //전체 문항 수 100개
const label = select[answerNum[0]].querySelectorAll("input") //보기 4개
label[answerNum[1]-1].checked = true;
const answerInputs = document.querySelectorAll(".cbt__selects input:checked")
cbtRest.innerHTML = questionLength - answerInputs.length;
}
//보기 체크2
const answerSelect = (el) => {
const answer = el.value; //value="${number}_1"
const answerNum = answer.split("_");
const select = document.querySelectorAll(".cbt__quiz .cbt"); //전체 문항 수 100개
const label = select[answerNum[0]].querySelectorAll("input") //보기 4개
label[answerNum[1]-1].checked = true;
const answerInputs = document.querySelectorAll(".cbt__selects input:checked")
cbtRest.innerHTML = questionLength - answerInputs.length;
}
cbtSubmit.addEventListener("click", answerQuiz);
dataQuestion();
</script>
전체 문제 수와 전체 문제 수에서 푼 문제 수를 뺀 남은 문제 수를 표현하기 위해서 추가한 부분들이 있습니다.
const cbtLength = document.querySelector(".cbt__length);
const cbtRest = document.querySelector(".cbt__rest);
전체 문제 수는 변수 cbtLength 에,
남은 문제 수는 변수 cbtRest 에 저장한 선택자를 만들었습니다.
questionLength = questionAll.length;
cbtLength.innerHTML = questionLength;
cbtRest.innerHTML = questionLength;
전체 문제 수는 퀴즈의 모든 정보를 가진 questionAll 변수의 길이를 세주는 .length를 사용한 값이므로,
questionLength 라는 변수를 정하고, 만들어 둔 선택자로 그 변수를 불러옵니다.
let questionLength = 0;
let questionRest = questionLength;
전체 문제 수에 0이라는 초기값을 주고,
남은 문제 수는 전체 문제 수라는 초기값을 줬습니다.
그리고 보기 두 가지의 보기 체크 부분들은 문제에서 객관식을 선택하거나 omr 답안지에서 객관식을 선택한 경우에 답이 선택되게 하기 위해서 추가한 부분들입니다.
split() 메서드는 문자열을 구분자로 구분하고, 여러 개의 문자열(배열)을 반환합니다.
"문자열".split(구분자, [제한])