한번씩 읽고 가세요.
“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”
- Frederick Philips Brooks
Mythical Man-Month 저자
퀴즈 유형 일곱번째 omr 체크하기
퀴즈유형 7번은 cbt 형식이고 omr형식으로 만들어 보았다.
json을 이용해 문제정보를 불러와 적용했다.
JSON이란
JSON(JavaScript Object Notation)은 사람이 읽고 쓰기 쉽고 기계가 구문 분석하고 생성하기 쉬운 경량 데이터 교환 형식입니다. XML의 대안으로 서버와 웹 애플리케이션 간에 데이터를 전송하는 데 자주 사용됩니다. JSON은 키-값 쌍과 배열로 구성되며 서로 다른 시스템 간에 데이터를 교환하기 위해 API(Application Programming Interface)에서 자주 사용됩니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>퀴즈 이펙트07</title>
<link rel="stylesheet" href="css.reset.css">
<link rel="stylesheet" href="css.quiz.css">
<!-- 파비콘 -->
<link rel="shortcut icon" type="image/x-icon" href="/site/site1/assets/ico/favicon.png">
<link rel="apple-touch-icon" sizes="114x114" href="/site/site1/assets/ico/favicon.png">
<link rel="apple-touch-icon" href="/site/site1/assets/ico/favicon.png">
</head>
<body>
<header id="header">
<h1><a href="../javascript14.html">Quiz</a><em>객관식 확인 CBT 유형</em></h1>
<ul>
<li><a href="quizEffect01.html">1</a></li>
<li><a href="quizEffect02.html">2</a></li>
<li><a href="quizEffect03.html">3</a></li>
<li><a href="quizEffect04.html">4</a></li>
<li><a href="quizEffect05.html">5</a></li>
<li><a href="quizEffect06.html">6</a></li>
<li class="active"><a href="quizEffect07.html">7</a></li>
<li><a href="quizEffect dc.html">d</a></li>
<li><a href="quizEffect webd.html">w</a></li>
</ul>
</header>
<!--//header-->
<main id="main">
<div class="quiz__wrap__cbt">
<div class="cbt__header">
<h2>2020년 1회 정보처리기능사 기출문제</h2>
<div>
</div>
</div>
<div class="cbt__conts">
<div class="cbt__quiz">
<!-- <div class="cbt">
<div class="cbt__question"><span>1</span>. 디자인의 요소 중 "형"에 대한 설명으로 옳지 않은 것은?</div>
<div class="cbt__question__img"><img src="assets/img/gineungsaJC2023_01-01.jpg" alt="기능사"></div>
<div class="cbt__selects">
<input type="radio" id="select1">
<label for="select1"><span>클래스</span></label>
<input type="radio" id="select2">
<label for="select2"><span>메소드</span></label>
<input type="radio" id="select3">
<label for="select3"><span>상속</span></label>
<input type="radio" id="select4">
<label for="select4"><span>메세지</span></label>
</div>
<div class="cbt__desc">객체지향언어는___이다.객체지향언어는___이다.객체지향언어는___이다.객체지향언어는___이다.객체지향언어는___이다.객체지향언어는___이다.객체지향언어는___이다.</div>
<div class="cbt__keyword"><span></span>객체지향언어</div>
</div> -->
</div>
</div>
<div class="right__frist">
<div class="cbt__time"><span>59초</span></div>
<div class="cbt__submit"><span>제출하기</span></div>
</div>
<div class="cbt__aside">
<div class="cbt__info">
<div class="cbt__title">수험자 : <em>김현빈</em></div>
<div class="cbt__score">
<span></span>
</div>
</div>
<div class="cbt__omr">
<!-- <div class="omr">
<strong>1</strong>
<input type="radio" id="omr0_1">
<label for="omr0_1">
<span class="label-inner">1</span>
</label>
<input type="radio" id="omr0_2">
<label for="omr0_2">
<span class="label-inner">2</span>
</label>
<input type="radio" id="omr0_3">
<label for="omr0_3">
<span class="label-inner">3</span>
</label>
<input type="radio" id="omr0_4">
<label for="omr0_4">
<span class="label-inner">4</span>
</label>
</div> -->
</div>
</div>
</div>
</main>
<!-- //main -->
<!-- <footer id="footer">
<a href="mailto:esansi@naver.com">esansi@naver.com</a>
</footer> -->
<!--//footer-->
<script>
let questionAll = []; //모든 퀴즈 정보
const cbtQuiz = document.querySelector(".cbt__quiz")
const cbtOmr = document.querySelector(".cbt__omr")
const cbtSubmit = document.querySelector(".cbt__submit")
const cbtScore = document.querySelector(".cbt__score span")
//데이터 불러오기
const dataQuestion = () => {
fetch("json/gineungsaWD2023_01.json")
.then(res => res.json()) //.then() .then () 체인 방식
.then(items => {
questionAll = items.map((item, index) => {
const formattedQuestion = {
question: item.question,
number: index + 1,
}
const answerChoices = [...item.incorrect_answers]; //오답 불러오기
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.questionDesc = item.question_desc;
}
//문제의 대한 이미지 있으면 출력
if (item.hasOwnProperty("question_img")) {
formattedQuestion.question_img = item.question_img;
}
//장답 해설이 있으면 출력
if (item.hasOwnProperty("desc")) {
formattedQuestion.desc = item.desc;
}
//장답 키워드 있으면 출력
// console.log(formattedQuestion);
return formattedQuestion;
})
newQuestion(); //문제만들기
})
.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"><img src="" alt=""></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=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].innerText == "undefined"){
quizDesc[number].classList.add("hide");
} else {
quizDesc[number].classList.remove("hide");
}
});
}
const answerSelect = () => {
}
cbtSubmit.addEventListener("click", answerQuiz);
dataQuestion();
</script>
</body>
</html>
cbt_quiz에 정보를 넣어줘야하기 때문에 일단 const cbtQuiz = document.querySelector(".cbt__quiz") 선택자를 만들어 준다.
그 문제 정보를 제이슨에서 받아오기 위해 변수 const dataQuestion을 만들어줍니다. 그 안에 fetch() 사용해 제이슨을 불러옵니다. 그 후 .then() 메서드를 체인 방식을 통해 써줍니다.
fetch()지정된 URL에 대한 네트워크 요청을 만들고 해당 요청에 대한 응답을 나타내는 Response 개체로 확인되는 Promise를 반환하는 데 사용되는 내장 JavaScript 함수입니다.
이 then()메서드는 에서 반환한 Promise에서 반환한 응답을 처리하는 데 사용됩니다 fetch(). Promise의 확인된 값을 처리하는 콜백 함수와 Promise의 거부된 값을 처리하는 두 번째 콜백 함수의 두 가지 매개변수를 사용합니다.
fetch("json/gineungsaWD2023_01.json")
.then(res => res.json()) //.then() .then () 체인 방식
.then(items => {}
문제의 정보 100개를 questionAll이라 하고 그 문제들을 반복하며 배열로 가져오기 위해 map()메서드를 사용합니다.
문제와 문제번호를 불러왔습니다.
items => {
questionAll = items.map((item, index) => {
const formattedQuestion = {
question: item.question,
number: index + 1,
}
그 후 오답과 정답을 불러오고 정답은 랜덤하게 배치 될 있게 random()과 floor() Math 수학 메서드를 사용합니다.
오답배열에 splice를 통해 정답을 넣어줍니다!
splice 메서드는 배열의 내용을 변경하는 데 사용됩니다. splice 메서드는 배열에서 요소를 추가, 제거 또는 교체할 수 있습니다.
그 후 문제마다 이미지가 있고 없고 각 기 다르기 때문에 if 문안에 hasOwnProperty 를 사용해 분류하여 나올수있게 한다.
hasOwnProperty는 객체의 속성(property) 중에서 해당 객체 자체에 속한 속성인지 확인하는 메서드입니다. 즉, 해당 객체에 직접적으로 정의된 속성인지 여부를 확인할 수 있습니다.
const answerChoices = [...item.incorrect_answers]; //오답 불러오기
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.questionDesc = item.question_desc;
}
//문제의 대한 이미지 있으면 출력
if (item.hasOwnProperty("question_img")) {
formattedQuestion.question_img = item.question_img;
}
//장답 해설이 있으면 출력
if (item.hasOwnProperty("desc")) {
formattedQuestion.desc = item.desc;
}
//장답 키워드 있으면 출력
// console.log(formattedQuestion);
return formattedQuestion;
그리고 변수 newQuestion을 만들어 그 안에 exam과omr을 변수로 만들어 그 배열 안에 문제를 템플릿리터럴 방식을 통해 넣어줍니다.
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"><img src="" alt=""></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=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('');
join을 통해 ,를 없애줍니다.
마지막으로는 사용자가 체크한 정답과 문제정보의 정답을 체크할수있고 그 정답끼리 일치하는지 일치하지 않는지를
변수들을 만들어준 후 조건문을 활용해 구분해줍니다.
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].innerText == "undefined"){
quizDesc[number].classList.add("hide");
} else {
quizDesc[number].classList.remove("hide");
}
});
}
const answerSelect = () => {
}
cbtSubmit.addEventListener("click", answerQuiz);
dataQuestion();